From 5174fd67581db8ed0822bc81eca928cce418db51 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 11 Oct 2026 11:36:39 -0400 Subject: [PATCH 01/45] Add candidate qualification contracts and the scorecard replay interface QualificationReceipt records a candidate pair, the policyengine.py commit that qualified it, every mandatory gate and a verdict that is a pure function of the gates. select_promotion_target picks the newest promotable pair that strictly advances the certified pair, independent of arrival order. The replay request, status and receipt mirror the scorecard's v1 JSON Schemas (vendored unchanged) and reproduce its golden digests. Refs #573 Co-Authored-By: Claude Opus 5.5 --- src/policyengine/data/qualification/uk.json | 30 + .../qualification_request.v1.json | 145 +++ .../replay_receipt.v1.json | 229 +++++ .../replay_status.v1.json | 36 + src/policyengine/provenance/qualification.py | 907 ++++++++++++++++++ 5 files changed, 1347 insertions(+) create mode 100644 src/policyengine/data/qualification/uk.json create mode 100644 src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json create mode 100644 src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json create mode 100644 src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_status.v1.json create mode 100644 src/policyengine/provenance/qualification.py diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json new file mode 100644 index 00000000..4e43592f --- /dev/null +++ b/src/policyengine/data/qualification/uk.json @@ -0,0 +1,30 @@ +{ + "schema_version": 1, + "country_id": "uk", + "required_years": [2025, 2026, 2027, 2028, 2029, 2030], + "budget_horizon_years": [2026, 2027, 2028, 2029, 2030, 2031], + "reform_contract": { + "entrypoint": "policyengine.tax_benefit_models.uk.budget_reform_contract:run_budget_reform_contract", + "seed": 0, + "max_examples": 50 + }, + "metrics": { + "entrypoint": null, + "years": [2025, 2026, 2027, 2028, 2029, 2030], + "bounds": "uk_review_bounds.json" + }, + "budget_inputs": { + "critical": "uk_budget_critical_inputs.json" + }, + "replay": { + "repository": "PolicyEngine/policyengine-scorecard", + "event_type": "uk-replay-qualification-request", + "state_ref": "replay-state", + "compare_to": "latest_certified", + "poll_timeout_minutes": 360 + }, + "promotion": { + "automatic": false, + "decision": "cos d1344: automatic promotion and review bounds are methodology calls; until ruled, promotion is a reviewed PR merge." + } +} diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json new file mode 100644 index 00000000..735b66c6 --- /dev/null +++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json @@ -0,0 +1,145 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/PolicyEngine/policyengine-scorecard/blob/main/docs/uk_replay/schemas/qualification_request.v1.json", + "title": "UK fiscal-event replay qualification request, v1", + "description": "Sent by policyengine.py release qualification (W4) to policyengine-scorecard (W6). request_id is the SHA-256 of the RFC 8785 (JCS) bytes of the whole request; it is never a field. Additive optional fields keep v1; renamed or removed fields bump the version.", + "type": "object", + "additionalProperties": false, + "required": ["schema", "kind", "attempt", "candidate", "compare_to", "requested_by"], + "properties": { + "schema": {"const": "policyengine.uk-replay-qualification-request/v1"}, + "kind": { + "description": "candidate: a pair not yet promoted; released_bundle: a published policyengine.py release.", + "enum": ["candidate", "released_bundle"] + }, + "attempt": { + "description": "A retry of a failed request is a new request with a higher attempt.", + "type": "integer", + "minimum": 1 + }, + "candidate": { + "type": "object", + "additionalProperties": false, + "required": ["policyengine", "policyengine_uk", "policyengine_core", "data", "expected_release_bundle"], + "properties": { + "policyengine": { + "type": "object", + "additionalProperties": false, + "required": ["version", "source", "packaged_bundle_manifest_sha256"], + "properties": { + "version": {"$ref": "#/$defs/version"}, + "source": { + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["git"], + "properties": { + "git": { + "type": "object", + "additionalProperties": false, + "required": ["repository", "commit"], + "properties": { + "repository": {"const": "PolicyEngine/policyengine.py"}, + "commit": {"$ref": "#/$defs/sha1"} + } + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["pypi"], + "properties": { + "pypi": { + "type": "object", + "additionalProperties": false, + "required": ["wheel_sha256"], + "properties": {"wheel_sha256": {"$ref": "#/$defs/sha256"}} + } + } + } + ] + }, + "packaged_bundle_manifest_sha256": {"$ref": "#/$defs/sha256"} + } + }, + "policyengine_uk": {"$ref": "#/$defs/pypi_package"}, + "policyengine_core": {"$ref": "#/$defs/pypi_package"}, + "data": { + "type": "object", + "additionalProperties": false, + "required": ["build_id", "dataset", "repo_id", "repo_type", "revision", "path", "sha256", "size_bytes", "release_manifest_sha256"], + "properties": { + "build_id": {"type": "string", "minLength": 1}, + "dataset": {"type": "string", "minLength": 1}, + "repo_id": {"type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"}, + "repo_type": {"enum": ["model", "dataset"]}, + "revision": {"type": "string", "minLength": 1}, + "path": {"type": "string", "minLength": 1, "pattern": "^[^/][^\\\\]*$"}, + "sha256": {"$ref": "#/$defs/sha256"}, + "size_bytes": {"type": "integer", "minimum": 1}, + "release_manifest_sha256": {"$ref": "#/$defs/sha256"} + } + }, + "expected_release_bundle": { + "description": "The exact dict(pe.uk.uk_latest.release_bundle) under packaged certification, computed with HF_TOKEN, HUGGING_FACE_TOKEN and HUGGINGFACE_HUB_TOKEN removed from the environment.", + "type": "object", + "required": ["policyengine_version", "model_version", "certified_data_build_id", "certified_data_artifact_sha256", "default_dataset_uri"], + "additionalProperties": {"type": ["string", "null"]}, + "properties": { + "policyengine_version": {"$ref": "#/$defs/version"}, + "model_version": {"$ref": "#/$defs/version"}, + "certified_data_build_id": {"type": "string", "minLength": 1}, + "certified_data_artifact_sha256": {"$ref": "#/$defs/sha256"}, + "default_dataset_uri": {"type": "string", "pattern": "^hf://"} + } + } + } + }, + "compare_to": { + "description": "latest_certified, or an explicit scorecard variant_id.", + "type": "string", + "minLength": 1 + }, + "requested_by": { + "type": "object", + "additionalProperties": true, + "required": ["repository", "workflow_run_id", "commit"], + "properties": { + "repository": {"type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"}, + "workflow_run_id": {"type": "integer", "minimum": 1}, + "run_attempt": {"type": "integer", "minimum": 1}, + "commit": {"$ref": "#/$defs/sha1"} + } + } + }, + "allOf": [ + { + "if": {"properties": {"kind": {"const": "released_bundle"}}}, + "then": { + "properties": { + "candidate": { + "properties": { + "policyengine": {"properties": {"source": {"required": ["pypi"]}}} + } + } + } + } + } + ], + "$defs": { + "sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "sha1": {"type": "string", "pattern": "^[0-9a-f]{40}$"}, + "version": {"type": "string", "pattern": "^[0-9]+(\\.[0-9]+)*([a-z0-9.+-]*)$"}, + "pypi_package": { + "type": "object", + "additionalProperties": false, + "required": ["version", "wheel_sha256"], + "properties": { + "version": {"$ref": "#/$defs/version"}, + "wheel_sha256": {"$ref": "#/$defs/sha256"} + } + } + } +} diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json new file mode 100644 index 00000000..2aac386c --- /dev/null +++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json @@ -0,0 +1,229 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/PolicyEngine/policyengine-scorecard/blob/main/docs/uk_replay/schemas/replay_receipt.v1.json", + "title": "UK fiscal-event replay receipt, v1", + "description": "Returned by policyengine-scorecard for one qualification request. receipt_sha256 is the SHA-256 of the RFC 8785 (JCS) bytes of the receipt without that field. Flags describe movements against the base variant; they carry no verdict.", + "type": "object", + "additionalProperties": false, + "required": ["schema", "request_id", "status", "rejection", "variant_id", "variant_identity_sha256", "execution", "corpus", "integrity", "diff", "results", "receipt_sha256"], + "properties": { + "schema": {"const": "policyengine.uk-replay-receipt/v1"}, + "request_id": {"$ref": "#/$defs/sha256"}, + "status": {"enum": ["complete", "rejected", "failed"]}, + "rejection": { + "oneOf": [ + {"type": "null"}, + { + "type": "object", + "additionalProperties": false, + "required": ["code", "detail"], + "properties": { + "code": {"enum": ["schema_invalid", "artifact_hash_mismatch", "release_bundle_mismatch", "incompatible_pair", "data_access_failed", "no_supported_years"]}, + "detail": {"type": "string", "minLength": 1} + } + } + ] + }, + "variant_id": {"type": ["string", "null"], "minLength": 1}, + "variant_identity_sha256": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/sha256"}]}, + "execution": { + "oneOf": [ + {"type": "null"}, + { + "type": "object", + "additionalProperties": false, + "required": ["packages", "packaged_bundle_manifest_sha256", "release_bundle", "dataset_sha256", "requirements_sha256", "python", "platform", "runner"], + "properties": { + "packages": { + "type": "object", + "additionalProperties": false, + "required": ["policyengine", "policyengine-uk", "policyengine-core"], + "properties": { + "policyengine": {"$ref": "#/$defs/installed_package"}, + "policyengine-uk": {"$ref": "#/$defs/installed_package"}, + "policyengine-core": {"$ref": "#/$defs/installed_package"} + } + }, + "packaged_bundle_manifest_sha256": {"$ref": "#/$defs/sha256"}, + "release_bundle": {"type": "object", "additionalProperties": {"type": ["string", "null"]}}, + "dataset_sha256": {"$ref": "#/$defs/sha256"}, + "requirements_sha256": {"$ref": "#/$defs/sha256"}, + "python": {"type": "string", "pattern": "^3\\.[0-9]+\\.[0-9]+"}, + "platform": {"type": "string", "minLength": 1}, + "runner": {"type": "string", "minLength": 1} + } + } + ] + }, + "corpus": { + "oneOf": [ + {"type": "null"}, + { + "type": "object", + "additionalProperties": false, + "required": ["corpus_version", "events"], + "properties": { + "corpus_version": {"type": "string", "minLength": 1}, + "events": { + "type": "object", + "minProperties": 1, + "additionalProperties": {"$ref": "#/$defs/event_result"} + } + } + } + ] + }, + "integrity": { + "type": "object", + "additionalProperties": false, + "required": ["status", "failures"], + "properties": { + "status": { + "description": "complete: every supported measure-year ran and every receipt verified. incomplete: some supported pairs are missing. failed: a crash, a non-finite value, an identity mismatch after the run started, or a broken accounting identity.", + "enum": ["complete", "incomplete", "failed", "not_run"] + }, + "failures": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["code", "detail"], + "properties": { + "code": {"type": "string", "minLength": 1}, + "detail": {"type": "string", "minLength": 1}, + "event": {"type": "string"}, + "measure_key": {"type": "string"}, + "year": {"type": "integer"} + } + } + } + } + }, + "diff": { + "oneOf": [ + {"type": "null"}, + { + "type": "object", + "additionalProperties": false, + "required": ["base_variant_id", "diff_sha256", "flag_counts", "flagged_rows"], + "properties": { + "base_variant_id": {"type": "string", "minLength": 1}, + "diff_sha256": {"$ref": "#/$defs/sha256"}, + "flag_counts": { + "type": "object", + "additionalProperties": false, + "required": ["numerical", "structural", "coverage", "mapping", "support", "inertness", "construction"], + "properties": { + "numerical": {"type": "integer", "minimum": 0}, + "structural": {"type": "integer", "minimum": 0}, + "coverage": {"type": "integer", "minimum": 0}, + "mapping": {"type": "integer", "minimum": 0}, + "support": {"type": "integer", "minimum": 0}, + "inertness": {"type": "integer", "minimum": 0}, + "construction": {"type": "integer", "minimum": 0} + } + }, + "flagged_rows": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["event", "measure_key", "year", "level", "key", "flags", "base_gbp", "head_gbp"], + "properties": { + "event": {"type": "string", "minLength": 1}, + "measure_key": {"type": "string", "minLength": 1}, + "year": {"type": "integer"}, + "level": {"enum": ["source_row", "measure_year", "head"]}, + "key": {"type": "string", "minLength": 1}, + "flags": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": {"enum": ["numerical", "structural", "coverage", "mapping", "support", "inertness", "construction"]} + }, + "base_gbp": {"type": ["number", "null"]}, + "head_gbp": {"type": ["number", "null"]} + } + } + } + } + } + ] + }, + "results": { + "type": "object", + "additionalProperties": false, + "required": ["repository", "ref", "path"], + "properties": { + "repository": {"const": "PolicyEngine/policyengine-scorecard"}, + "ref": {"type": "string", "minLength": 1}, + "commit": {"$ref": "#/$defs/sha1"}, + "path": {"type": "string", "minLength": 1} + } + }, + "receipt_sha256": {"$ref": "#/$defs/sha256"} + }, + "allOf": [ + { + "if": {"properties": {"status": {"const": "rejected"}}}, + "then": {"properties": {"rejection": {"type": "object"}, "corpus": {"type": "null"}, "diff": {"type": "null"}}} + }, + { + "if": {"properties": {"status": {"enum": ["complete", "failed"]}}}, + "then": {"properties": {"rejection": {"type": "null"}, "variant_id": {"type": "string"}, "execution": {"type": "object"}}} + }, + { + "if": {"properties": {"status": {"const": "complete"}}}, + "then": {"properties": {"integrity": {"properties": {"status": {"enum": ["complete", "incomplete"]}}}, "corpus": {"type": "object"}}} + } + ], + "$defs": { + "sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "sha1": {"type": "string", "pattern": "^[0-9a-f]{40}$"}, + "installed_package": { + "type": "object", + "additionalProperties": false, + "required": ["version", "record_sha256"], + "properties": { + "version": {"type": "string", "minLength": 1}, + "record_sha256": {"$ref": "#/$defs/sha256"}, + "wheel_sha256": {"$ref": "#/$defs/sha256"} + } + }, + "event_result": { + "type": "object", + "additionalProperties": false, + "required": ["registry_sha256", "supported_years", "unsupported_years", "run_manifest_sha256", "staging_manifest_sha256", "comparison_provenance_sha256", "artifacts", "full_supported_grid_complete", "inert_measure_years"], + "properties": { + "registry_sha256": {"$ref": "#/$defs/sha256"}, + "supported_years": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, + "unsupported_years": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["year", "reason"], + "properties": { + "year": {"type": "integer"}, + "reason": {"enum": ["before_data_year", "after_extension_end"]} + } + } + }, + "run_manifest_sha256": {"$ref": "#/$defs/sha256"}, + "staging_manifest_sha256": {"$ref": "#/$defs/sha256"}, + "comparison_provenance_sha256": {"$ref": "#/$defs/sha256"}, + "artifacts": {"type": "integer", "minimum": 0}, + "full_supported_grid_complete": {"type": "boolean"}, + "inert_measure_years": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["measure_key", "year"], + "properties": {"measure_key": {"type": "string"}, "year": {"type": "integer"}} + } + } + } + } + } +} diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_status.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_status.v1.json new file mode 100644 index 00000000..3694ca4e --- /dev/null +++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_status.v1.json @@ -0,0 +1,36 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/PolicyEngine/policyengine-scorecard/blob/main/docs/uk_replay/schemas/replay_status.v1.json", + "title": "UK fiscal-event replay request status, v1", + "description": "replay-state:requests//STATUS.json. A terminal status names the receipt's digest and the replay-state commit that added REPLAY_RECEIPT.json, so one contents read binds the status to the receipt bytes.", + "type": "object", + "additionalProperties": false, + "required": ["schema", "request_id", "status", "history"], + "properties": { + "schema": {"const": "policyengine.uk-replay-status/v1"}, + "request_id": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "status": {"enum": ["queued", "running", "complete", "rejected", "failed"]}, + "history": { + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "additionalProperties": false, + "required": ["status", "at", "run_url"], + "properties": { + "status": {"enum": ["queued", "running", "complete", "rejected", "failed"]}, + "at": {"type": "string", "format": "date-time"}, + "run_url": {"type": "string", "pattern": "^https://github\\.com/PolicyEngine/policyengine-scorecard/actions/runs/[0-9]+"} + } + } + }, + "receipt_sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, + "receipt_commit": {"type": "string", "pattern": "^[0-9a-f]{40}$"} + }, + "allOf": [ + { + "if": {"properties": {"status": {"enum": ["complete", "rejected", "failed"]}}}, + "then": {"required": ["receipt_sha256", "receipt_commit"]} + } + ] +} diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py new file mode 100644 index 00000000..bcfeb016 --- /dev/null +++ b/src/policyengine/provenance/qualification.py @@ -0,0 +1,907 @@ +"""Candidate qualification contracts and pure decision rules. + +A *candidate* is a country model wheel, its core wheel and a data release +that are not yet certified together. Qualification: + +1. prepares a policyengine.py commit whose packaged manifest, pins, lock and + TRO certify the pair (the candidate commit, which is also what promotion + merges); +2. runs mandatory local gates on that commit (:data:`REQUIRED_GATES`); +3. sends the replay corpus owner (policyengine-scorecard) an immutable + :class:`ReplayQualificationRequest`, polls its :class:`ReplayStatus` and + checks the :class:`ReplayReceipt` against the request + (:func:`evaluate_replay_receipt`); +4. records a :class:`QualificationReceipt` whose verdict is a pure function of + the gate results (:func:`qualification_verdict`). + +Promotion then picks the newest promotable pair that strictly advances the +certified pair (:func:`select_promotion_target`), so a stale completion +cannot displace a newer accepted candidate. + +The replay request, status and receipt mirror the JSON Schemas published by +policyengine-scorecard (vendored, unchanged, in +``policyengine/data/schemas/vendor/policyengine-scorecard/``). Their digests +are plain RFC 8785 over the document as sent, nulls included, which is what +the scorecard computes. W4's own receipts use the receipt-v1 rule of +:func:`policyengine.provenance.receipt.content_sha256` (nulls dropped). +""" + +from __future__ import annotations + +from collections.abc import Iterable, Mapping, Sequence +from typing import Any, ClassVar, Literal, Optional + +from packaging.version import Version +from pydantic import ( + BaseModel, + ConfigDict, + Field, + PrivateAttr, + field_validator, + model_validator, +) + +from policyengine.provenance.canonical import canonical_sha256 +from policyengine.provenance.receipt import ( + GIT_SHA_PATTERN, + SHA256_PATTERN, + _Contract, + content_sha256, +) + +__all__ = [ + "BLOCKING_REPLAY_FLAGS", + "REQUIRED_GATES", + "REVIEW_REPLAY_FLAGS", + "CandidatePair", + "GateResult", + "QualificationHarness", + "QualificationReceipt", + "ReplayQualificationRequest", + "ReplayReceipt", + "ReplayStatus", + "ReviewAcceptance", + "dominates", + "evaluate_replay_receipt", + "qualification_verdict", + "select_promotion_target", +] + +# --- Gate results and verdicts ------------------------------------------ + +GateStatus = Literal["pass", "needs_review", "unavailable", "fail", "error"] +Verdict = Literal["qualified", "needs_review", "incomplete", "rejected"] + +#: Every mandatory gate. A gate has no "skipped" status: a gate whose harness +#: is missing reports ``unavailable`` (the candidate is then incomplete, not +#: promotable), a gate that crashed while evaluating the candidate reports +#: ``error`` (the candidate is rejected), and a gate that never reported +#: leaves the qualification incomplete. +REQUIRED_GATES: tuple[str, ...] = ( + "installed_versions", + "wheel_hashes", + "core_compatibility", + "data_access", + "dataset_bytes", + "supported_years", + "budget_inputs", + "reform_contract", + "metrics_review", + "replay", +) + +_SEVERITY: dict[str, int] = { + "pass": 0, + "needs_review": 1, + "unavailable": 2, + "fail": 3, + "error": 3, +} + +#: Replay diff flags that block promotion whatever their size. Proposed +#: policy pending cos d1344; numerical and support flags need review. +BLOCKING_REPLAY_FLAGS: frozenset[str] = frozenset( + {"structural", "coverage", "mapping", "inertness", "construction"} +) +REVIEW_REPLAY_FLAGS: frozenset[str] = frozenset({"numerical", "support"}) + + +class GateResult(_Contract): + """One mandatory qualification gate.""" + + gate_id: str + status: GateStatus + summary: str = Field(min_length=1) + evidence_sha256: Optional[str] = Field( + default=None, + pattern=SHA256_PATTERN, + description="content_sha256 of the evidence JSON stored with the receipt.", + ) + details: dict[str, Any] = Field(default_factory=dict) + + +def qualification_verdict(gates: Iterable[GateResult]) -> Verdict: + """The verdict a set of gate results determines. + + - ``rejected`` if any gate failed or errored; + - otherwise ``incomplete`` if any gate is unavailable or a required gate + did not report; + - otherwise ``needs_review`` if any gate needs review; + - otherwise ``qualified``. + + Making any gate worse never makes the verdict better. + """ + + gates = list(gates) + worst = max((_SEVERITY[gate.status] for gate in gates), default=0) + if worst >= _SEVERITY["fail"]: + return "rejected" + reported = {gate.gate_id for gate in gates} + if worst == _SEVERITY["unavailable"] or any( + gate_id not in reported for gate_id in REQUIRED_GATES + ): + return "incomplete" + if worst == _SEVERITY["needs_review"]: + return "needs_review" + return "qualified" + + +# --- What is qualified ---------------------------------------------------- + + +class PinnedWheel(_Contract): + name: str + version: str + wheel_sha256: str = Field(pattern=SHA256_PATTERN) + + +class PinnedData(_Contract): + data_package: str + release_version: str + build_id: str + repo_id: str + repo_type: Literal["model", "dataset"] + release_manifest_path: str + release_manifest_revision: str + release_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + dataset: str + dataset_path: str + dataset_revision: str + dataset_sha256: str = Field(pattern=SHA256_PATTERN) + size_bytes: int = Field(ge=1) + + +class CandidatePair(_Contract): + """The model, core and data that would be certified together. + + ``pair_id`` (its receipt-v1 digest) does not depend on the policyengine.py + commit, so the candidate commit's manifest can name the pair it certifies. + """ + + country_id: Literal["uk"] + model: PinnedWheel + core: PinnedWheel + data: PinnedData + + @property + def pair_id(self) -> str: + return content_sha256(self.canonical_payload()) + + @property + def order_key(self) -> tuple[str, str, str]: + """(model version, data release, core version): what promotion orders.""" + + return (self.model.version, self.data.release_version, self.core.version) + + +class QualificationHarness(_Contract): + """The policyengine.py commit that carried and ran the qualification.""" + + policyengine_version: str + git_commit: str = Field(pattern=GIT_SHA_PATTERN) + packaged_bundle_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + + +class IssuedBy(_Contract): + repository: str = Field(pattern=r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") + workflow_run_id: int = Field(ge=1) + run_attempt: int = Field(default=1, ge=1) + run_url: str + + +class PreviousCertificate(_Contract): + """The certified pair a candidate would replace.""" + + bundle_version: str + model_version: str + core_version: str + data_release_version: str + dataset_sha256: str = Field(pattern=SHA256_PATTERN) + certificate_sha256: str = Field(pattern=SHA256_PATTERN) + + +class ReplayReference(_Contract): + request_id: str = Field(pattern=SHA256_PATTERN) + receipt_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN) + receipt_commit: Optional[str] = Field(default=None, pattern=GIT_SHA_PATTERN) + + +class ReviewAcceptance(_Contract): + """A reviewer's acceptance of one exact needs-review receipt.""" + + reviewer: str = Field(min_length=1) + accepted_at: str + accepted_receipt_sha256: str = Field( + pattern=SHA256_PATTERN, + description="unreviewed_sha256 of the receipt being accepted.", + ) + explanation: str = Field(min_length=1) + + +class QualificationReceipt(_Contract): + """The qualification outcome recorded in the ledger for one candidate.""" + + SCHEMA_ID: ClassVar[str] = ( + "https://policyengine.org/schemas/candidate_qualification_receipt.v1.json" + ) + + schema_version: Literal[1] + receipt_type: Literal["policyengine.candidate_qualification_receipt"] + pair_id: str = Field(pattern=SHA256_PATTERN) + pair: CandidatePair + harness: QualificationHarness + previous_certificate: Optional[PreviousCertificate] = None + replay: Optional[ReplayReference] = None + gates: list[GateResult] + verdict: Verdict + review: Optional[ReviewAcceptance] = None + issued_by: IssuedBy + completed_at: str = Field(description="ISO 8601 UTC, e.g. 2026-10-15T09:30:00Z.") + + @model_validator(mode="after") + def _consistent(self) -> QualificationReceipt: + if self.pair_id != self.pair.pair_id: + raise ValueError("pair_id is not the digest of pair.") + ids = [gate.gate_id for gate in self.gates] + if len(ids) != len(set(ids)): + raise ValueError("Each gate reports at most once.") + expected = qualification_verdict(self.gates) + if self.verdict != expected: + raise ValueError( + f"verdict {self.verdict!r} does not follow from the gates ({expected!r})." + ) + if self.review is not None and self.verdict != "needs_review": + raise ValueError("Only a needs-review verdict can be accepted on review.") + return self + + @property + def unreviewed_sha256(self) -> str: + """Digest of the receipt without ``review``: what a review accepts.""" + + payload = self.canonical_payload() + payload.pop("review", None) + return content_sha256(payload) + + @property + def receipt_sha256(self) -> str: + return content_sha256(self.canonical_payload()) + + @property + def promotable(self) -> bool: + """Qualified, or needs review with an acceptance of exactly this receipt.""" + + if self.verdict == "qualified": + return True + return ( + self.verdict == "needs_review" + and self.review is not None + and self.review.accepted_receipt_sha256 == self.unreviewed_sha256 + ) + + +# --- Promotion order ------------------------------------------------------ + + +def _versions(key: Sequence[str]) -> tuple[Version, ...]: + return tuple(Version(part) for part in key) + + +def dominates(newer: Sequence[str], older: Sequence[str]) -> bool: + """``newer`` is at least ``older`` in every component and differs from it.""" + + a, b = _versions(newer), _versions(older) + if len(a) != len(b): + raise ValueError("Order keys must have the same length.") + return a != b and all(x >= y for x, y in zip(a, b)) + + +def select_promotion_target( + receipts: Iterable[QualificationReceipt], + current: Optional[Sequence[str]], +) -> Optional[QualificationReceipt]: + """The promotable candidate to promote next, or ``None``. + + Eligible receipts are promotable and strictly advance ``current`` (model + version, data release, core version). Among them the target is the one + whose pair dominates every other eligible pair. If eligible pairs have no + single newest member (a newer model with an older data release, say), + nothing is promoted automatically. The result depends only on the set of + receipts, never on the order they arrive in. + """ + + eligible: dict[tuple[str, ...], QualificationReceipt] = {} + for receipt in receipts: + if not receipt.promotable: + continue + key = tuple(receipt.pair.order_key) + if current is not None and not dominates(key, current): + continue + incumbent = eligible.get(key) + if incumbent is None or (receipt.completed_at, receipt.receipt_sha256) > ( + incumbent.completed_at, + incumbent.receipt_sha256, + ): + eligible[key] = receipt + keys = list(eligible) + for key in keys: + if all(other == key or dominates(key, other) for other in keys): + return eligible[key] + return None + + +# --- Replay interface (mirrors policyengine-scorecard schemas v1) --------- + + +class _Mirror(BaseModel): + """Closed, immutable mirror of a scorecard JSON Schema object.""" + + model_config = ConfigDict(frozen=True, extra="forbid", populate_by_name=True) + + def document(self) -> dict[str, Any]: + """The JSON document exactly as the scorecard schema spells it.""" + + return self.model_dump(mode="json", by_alias=True, exclude_none=True) + + +class _Open(_Mirror): + model_config = ConfigDict(frozen=True, extra="allow", populate_by_name=True) + + +_SHA1 = GIT_SHA_PATTERN +_VERSION = r"^[0-9]+(\.[0-9]+)*([a-z0-9.+-]*)$" + + +class GitSource(_Mirror): + repository: Literal["PolicyEngine/policyengine.py"] + commit: str = Field(pattern=_SHA1) + + +class PypiSource(_Mirror): + wheel_sha256: str = Field(pattern=SHA256_PATTERN) + + +class WrapperSource(_Mirror): + git: Optional[GitSource] = None + pypi: Optional[PypiSource] = None + + @model_validator(mode="after") + def _one_source(self) -> WrapperSource: + if (self.git is None) == (self.pypi is None): + raise ValueError("The wrapper source is exactly one of git or pypi.") + return self + + +class RequestWrapper(_Mirror): + version: str = Field(pattern=_VERSION) + source: WrapperSource + packaged_bundle_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + + +class RequestPackage(_Mirror): + version: str = Field(pattern=_VERSION) + wheel_sha256: str = Field(pattern=SHA256_PATTERN) + + +class RequestData(_Mirror): + build_id: str = Field(min_length=1) + dataset: str = Field(min_length=1) + repo_id: str = Field(pattern=r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") + repo_type: Literal["model", "dataset"] + revision: str = Field(min_length=1) + path: str = Field(min_length=1, pattern=r"^[^/][^\\]*$") + sha256: str = Field(pattern=SHA256_PATTERN) + size_bytes: int = Field(ge=1) + release_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + + +class RequestCandidate(_Mirror): + policyengine: RequestWrapper + policyengine_uk: RequestPackage + policyengine_core: RequestPackage + data: RequestData + expected_release_bundle: dict[str, Optional[str]] + + @field_validator("expected_release_bundle") + @classmethod + def _required_bundle_fields( + cls, bundle: dict[str, Optional[str]] + ) -> dict[str, Optional[str]]: + for key in ( + "policyengine_version", + "model_version", + "certified_data_build_id", + "certified_data_artifact_sha256", + "default_dataset_uri", + ): + if not bundle.get(key): + raise ValueError(f"expected_release_bundle needs {key}.") + return bundle + + +class RequestedBy(_Open): + repository: str = Field(pattern=r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$") + workflow_run_id: int = Field(ge=1) + run_attempt: Optional[int] = Field(default=None, ge=1) + commit: str = Field(pattern=_SHA1) + + +class ReplayQualificationRequest(_Mirror): + """``policyengine.uk-replay-qualification-request/v1``.""" + + schema_id: Literal["policyengine.uk-replay-qualification-request/v1"] = Field( + alias="schema" + ) + kind: Literal["candidate", "released_bundle"] + attempt: int = Field(ge=1) + candidate: RequestCandidate + compare_to: str = Field(min_length=1) + requested_by: RequestedBy + + @model_validator(mode="after") + def _released_bundles_come_from_pypi(self) -> ReplayQualificationRequest: + if ( + self.kind == "released_bundle" + and self.candidate.policyengine.source.pypi is None + ): + raise ValueError("A released_bundle request names the PyPI wheel.") + return self + + @property + def request_id(self) -> str: + """Plain RFC 8785 SHA-256 of the request document, as the scorecard computes.""" + + return canonical_sha256(self.document()) + + +class StatusEvent(_Mirror): + status: Literal["queued", "running", "complete", "rejected", "failed"] + at: str + run_url: str = Field( + pattern=r"^https://github\.com/PolicyEngine/policyengine-scorecard/actions/runs/[0-9]+" + ) + + +class ReplayStatus(_Mirror): + """``policyengine.uk-replay-status/v1`` (``requests//STATUS.json``).""" + + schema_id: Literal["policyengine.uk-replay-status/v1"] = Field(alias="schema") + request_id: str = Field(pattern=SHA256_PATTERN) + status: Literal["queued", "running", "complete", "rejected", "failed"] + history: list[StatusEvent] = Field(min_length=1) + receipt_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN) + receipt_commit: Optional[str] = Field(default=None, pattern=_SHA1) + + @model_validator(mode="after") + def _terminal_names_receipt(self) -> ReplayStatus: + if self.terminal and ( + self.receipt_sha256 is None or self.receipt_commit is None + ): + raise ValueError("A terminal status names its receipt digest and commit.") + return self + + @property + def terminal(self) -> bool: + return self.status in ("complete", "rejected", "failed") + + +class Rejection(_Mirror): + code: Literal[ + "schema_invalid", + "artifact_hash_mismatch", + "release_bundle_mismatch", + "incompatible_pair", + "data_access_failed", + "no_supported_years", + ] + detail: str = Field(min_length=1) + + +class InstalledPackage(_Mirror): + version: str = Field(min_length=1) + record_sha256: str = Field(pattern=SHA256_PATTERN) + wheel_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN) + + +class ExecutedPackages(_Mirror): + policyengine: InstalledPackage + policyengine_uk: InstalledPackage = Field(alias="policyengine-uk") + policyengine_core: InstalledPackage = Field(alias="policyengine-core") + + +class Execution(_Mirror): + packages: ExecutedPackages + packaged_bundle_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + release_bundle: dict[str, Optional[str]] + dataset_sha256: str = Field(pattern=SHA256_PATTERN) + requirements_sha256: str = Field(pattern=SHA256_PATTERN) + python: str = Field(pattern=r"^3\.[0-9]+\.[0-9]+") + platform: str = Field(min_length=1) + runner: str = Field(min_length=1) + + +class UnsupportedYear(_Mirror): + year: int + reason: Literal["before_data_year", "after_extension_end"] + + +class InertMeasureYear(_Mirror): + measure_key: str + year: int + + +class EventResult(_Mirror): + registry_sha256: str = Field(pattern=SHA256_PATTERN) + supported_years: list[int] + unsupported_years: list[UnsupportedYear] + run_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + staging_manifest_sha256: str = Field(pattern=SHA256_PATTERN) + comparison_provenance_sha256: str = Field(pattern=SHA256_PATTERN) + artifacts: int = Field(ge=0) + full_supported_grid_complete: bool + inert_measure_years: list[InertMeasureYear] + + +class Corpus(_Mirror): + corpus_version: str = Field(min_length=1) + events: dict[str, EventResult] = Field(min_length=1) + + +class IntegrityFailure(_Mirror): + code: str = Field(min_length=1) + detail: str = Field(min_length=1) + event: Optional[str] = None + measure_key: Optional[str] = None + year: Optional[int] = None + + +class Integrity(_Mirror): + status: Literal["complete", "incomplete", "failed", "not_run"] + failures: list[IntegrityFailure] + + +FlagKind = Literal[ + "numerical", + "structural", + "coverage", + "mapping", + "support", + "inertness", + "construction", +] + + +class FlagCounts(_Mirror): + numerical: int = Field(ge=0) + structural: int = Field(ge=0) + coverage: int = Field(ge=0) + mapping: int = Field(ge=0) + support: int = Field(ge=0) + inertness: int = Field(ge=0) + construction: int = Field(ge=0) + + +class FlaggedRow(_Mirror): + event: str = Field(min_length=1) + measure_key: str = Field(min_length=1) + year: int + level: Literal["source_row", "measure_year", "head"] + key: str = Field(min_length=1) + flags: list[FlagKind] = Field(min_length=1) + base_gbp: Optional[float] = None + head_gbp: Optional[float] = None + + +class Diff(_Mirror): + base_variant_id: str = Field(min_length=1) + diff_sha256: str = Field(pattern=SHA256_PATTERN) + flag_counts: FlagCounts + flagged_rows: list[FlaggedRow] + + +class ResultsLocation(_Mirror): + repository: Literal["PolicyEngine/policyengine-scorecard"] + ref: str = Field(min_length=1) + commit: Optional[str] = Field(default=None, pattern=_SHA1) + path: str = Field(min_length=1) + + +class ReplayReceipt(_Mirror): + """``policyengine.uk-replay-receipt/v1`` (``requests//REPLAY_RECEIPT.json``). + + Nullable members are kept as ``null`` in :meth:`document`, because the + scorecard's ``receipt_sha256`` covers them. + """ + + schema_id: Literal["policyengine.uk-replay-receipt/v1"] = Field(alias="schema") + request_id: str = Field(pattern=SHA256_PATTERN) + status: Literal["complete", "rejected", "failed"] + rejection: Optional[Rejection] + variant_id: Optional[str] + variant_identity_sha256: Optional[str] = Field(pattern=SHA256_PATTERN) + execution: Optional[Execution] + corpus: Optional[Corpus] + integrity: Integrity + diff: Optional[Diff] + results: ResultsLocation + receipt_sha256: str = Field(pattern=SHA256_PATTERN) + + _received: Optional[dict[str, Any]] = PrivateAttr(default=None) + + @classmethod + def from_document(cls, document: Mapping[str, Any]) -> ReplayReceipt: + """Parse a received receipt, keeping its bytes for digest checks.""" + + receipt = cls.model_validate(dict(document)) + receipt._received = dict(document) + return receipt + + def document(self) -> dict[str, Any]: + """The received document if there is one, else this model's spelling.""" + + if self._received is not None: + return dict(self._received) + top = self.model_dump(mode="json", by_alias=True, exclude_none=False) + for key in ("rejection", "execution", "corpus", "diff", "results", "integrity"): + value = getattr(self, key) + top[key] = value.document() if value is not None else None + return top + + @property + def computed_receipt_sha256(self) -> str: + """Plain RFC 8785 SHA-256 of the receipt without ``receipt_sha256``.""" + + document = self.document() + document.pop("receipt_sha256", None) + return canonical_sha256(document) + + @model_validator(mode="after") + def _status_shape(self) -> ReplayReceipt: + if self.status == "rejected": + if ( + self.rejection is None + or self.corpus is not None + or self.diff is not None + ): + raise ValueError( + "A rejected receipt has a rejection and no corpus or diff." + ) + else: + if ( + self.rejection is not None + or self.variant_id is None + or self.execution is None + ): + raise ValueError( + f"A {self.status} receipt has a variant and an execution." + ) + if self.status == "complete" and ( + self.integrity.status not in ("complete", "incomplete") + or self.corpus is None + ): + raise ValueError("A complete receipt has a corpus and a run integrity.") + return self + + +def evaluate_replay_receipt( + request: ReplayQualificationRequest, + status: ReplayStatus, + receipt: ReplayReceipt, +) -> GateResult: + """The ``replay`` gate for a terminal replay status and its receipt. + + The receipt must answer this exact request, be the bytes the status + names, and report an execution of exactly the requested artifacts. + Rejected or failed replays, incomplete runs and blocking flags fail the + gate; numerical and support flags need review. Unsupported years are + reported, never failed on their own. + """ + + request_id = request.request_id + problems: list[str] = [] + if status.request_id != request_id or receipt.request_id != request_id: + problems.append("status or receipt answers a different request") + if not status.terminal: + problems.append(f"replay is still {status.status}") + if status.status != receipt.status and status.terminal: + problems.append("status and receipt disagree on the outcome") + if receipt.computed_receipt_sha256 != receipt.receipt_sha256: + problems.append("receipt_sha256 does not match the receipt bytes") + if status.receipt_sha256 != receipt.receipt_sha256: + problems.append("status names different receipt bytes") + + details: dict[str, Any] = { + "request_id": request_id, + "receipt_sha256": receipt.receipt_sha256, + "receipt_commit": status.receipt_commit, + "status": receipt.status, + "integrity": receipt.integrity.status, + } + if problems: + return GateResult( + gate_id="replay", + status="fail", + summary="Replay receipt is not bound to this request: " + + "; ".join(problems), + details={**details, "binding_problems": problems}, + ) + if receipt.status == "rejected": + assert receipt.rejection is not None + return GateResult( + gate_id="replay", + status="fail", + summary=f"Replay rejected the candidate ({receipt.rejection.code}): {receipt.rejection.detail}", + details={**details, "rejection": receipt.rejection.document()}, + ) + + execution = receipt.execution + assert execution is not None + candidate = request.candidate + mismatches: list[str] = [] + packages = { + "policyengine": ( + execution.packages.policyengine, + candidate.policyengine.version, + None, + ), + "policyengine-uk": ( + execution.packages.policyengine_uk, + candidate.policyengine_uk.version, + candidate.policyengine_uk.wheel_sha256, + ), + "policyengine-core": ( + execution.packages.policyengine_core, + candidate.policyengine_core.version, + candidate.policyengine_core.wheel_sha256, + ), + } + for name, (installed, version, wheel) in packages.items(): + if installed.version != version: + mismatches.append(f"{name} {installed.version} ran, not {version}") + if wheel is not None and installed.wheel_sha256 not in (None, wheel): + mismatches.append(f"{name} wheel hash differs from the request") + if ( + execution.packaged_bundle_manifest_sha256 + != candidate.policyengine.packaged_bundle_manifest_sha256 + ): + mismatches.append("packaged bundle manifest differs from the request") + if execution.dataset_sha256 != candidate.data.sha256: + mismatches.append("dataset bytes differ from the request") + if execution.release_bundle != candidate.expected_release_bundle: + mismatches.append("release bundle differs from the expected release bundle") + if mismatches: + return GateResult( + gate_id="replay", + status="fail", + summary="Replay ran something other than the candidate: " + + "; ".join(mismatches), + details={**details, "execution_mismatches": mismatches}, + ) + + if receipt.status == "failed" or receipt.integrity.status == "failed": + codes = sorted({failure.code for failure in receipt.integrity.failures}) + return GateResult( + gate_id="replay", + status="fail", + summary="Replay integrity failed: " + + (", ".join(codes) or "no failure codes"), + details={ + **details, + "integrity_failures": [ + f.document() for f in receipt.integrity.failures + ], + }, + ) + corpus = receipt.corpus + assert corpus is not None + incomplete_events = sorted( + name + for name, event in corpus.events.items() + if not event.full_supported_grid_complete + ) + unsupported = sorted( + (name, item.year, item.reason) + for name, event in corpus.events.items() + for item in event.unsupported_years + ) + inert = sorted( + (name, item.measure_key, item.year) + for name, event in corpus.events.items() + for item in event.inert_measure_years + ) + details.update( + { + "corpus_version": corpus.corpus_version, + "events": sorted(corpus.events), + "unsupported_years": [list(item) for item in unsupported], + "inert_measure_years": [list(item) for item in inert], + } + ) + if receipt.integrity.status != "complete" or incomplete_events: + return GateResult( + gate_id="replay", + status="fail", + summary=( + "Replay did not complete every supported measure-year" + + (f" ({', '.join(incomplete_events)})" if incomplete_events else "") + + "; mandatory gates take no partial evidence." + ), + details={**details, "incomplete_events": incomplete_events}, + ) + counts = receipt.diff.flag_counts.document() if receipt.diff is not None else {} + details["flag_counts"] = counts + if receipt.diff is not None: + details["base_variant_id"] = receipt.diff.base_variant_id + details["diff_sha256"] = receipt.diff.diff_sha256 + blocking = { + kind: n for kind, n in counts.items() if kind in BLOCKING_REPLAY_FLAGS and n + } + review = { + kind: n for kind, n in counts.items() if kind in REVIEW_REPLAY_FLAGS and n + } + if blocking: + return GateResult( + gate_id="replay", + status="fail", + summary="Blocking replay flags: " + + ", ".join(f"{kind} {n}" for kind, n in sorted(blocking.items())), + details=details, + ) + if review: + return GateResult( + gate_id="replay", + status="needs_review", + summary="Replay moves need review: " + + ", ".join(f"{kind} {n}" for kind, n in sorted(review.items())), + details=details, + ) + if receipt.diff is None: + return GateResult( + gate_id="replay", + status="needs_review", + summary="Replay completed but reported no diff against a certified variant.", + details=details, + ) + return GateResult( + gate_id="replay", + status="pass", + summary=f"Replayed {len(corpus.events)} event(s) with no flags against {receipt.diff.base_variant_id}.", + details=details, + ) + + +def replay_gate_while_pending(status: Optional[ReplayStatus]) -> GateResult: + """Gate result for a replay that has not reached a terminal status.""" + + state = status.status if status is not None else "not yet queued" + return GateResult( + gate_id="replay", + status="unavailable", + summary=f"Replay is {state}; the candidate stays incomplete until it finishes.", + details={"status": state}, + ) + + +def mirror_from_document(model: type[_Mirror], document: Mapping[str, Any]) -> Any: + """Parse a scorecard document into its mirror model.""" + + return model.model_validate(dict(document)) From 2722a718cf818de65b0c3aef8d1b2775c6d063ed Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sun, 11 Oct 2026 15:35:13 -0400 Subject: [PATCH 02/45] Qualify UK candidates: gates, ledger, ordered promotion and release dispatch Adds the certify-uk-release workflow and scripts/check_uk_candidate.py: resolve and deduplicate a candidate pair, build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, run the mandatory gates on it (no skips), send the scorecard an immutable replay request, record the qualification receipt in the ledger branch, and promote the newest promotable pair in order. Certification gains an exact qualified_exact_pair basis tied to a ledger receipt and a core check; the runtime honours it only for exactly its model and data build. The release dispatch carries the certified bundle identity and reaches the dashboard and the scorecard without risking the existing consumers. Refs #573 Co-Authored-By: Claude Opus 5.5 --- .github/dispatch-policyengine-release.sh | 49 +- .github/qualification-ledger.sh | 66 + .github/workflows/certify-uk-release.yaml | 418 +++++ .github/workflows/push.yaml | 74 +- changelog.d/573.added.md | 1 + scripts/bundle.py | 12 + scripts/certify_data_release.py | 18 + scripts/check_uk_candidate.py | 572 ++++++ scripts/release_consumers.py | 162 ++ src/policyengine/data/qualification/uk.json | 9 +- .../uk_budget_critical_inputs.json | 58 + .../data/qualification/uk_review_bounds.json | 74 + .../vendor/policyengine-scorecard/README.md | 9 + .../replay_receipt.v1.json | 539 +++++- src/policyengine/provenance/certification.py | 121 +- src/policyengine/provenance/manifest.py | 30 +- src/policyengine/provenance/qualification.py | 5 + .../provenance/qualification_ledger.py | 189 ++ src/policyengine/provenance/uk_candidate.py | 1560 +++++++++++++++++ .../provenance/uk_qualification.py | 1072 +++++++++++ tests/qualification_fixtures.py | 102 ++ tests/test_qualification_contracts.py | 446 +++++ tests/test_qualified_pair_certification.py | 387 ++++ tests/test_uk_candidate_gates.py | 994 +++++++++++ tests/test_uk_qualification_pipeline.py | 566 ++++++ 25 files changed, 7422 insertions(+), 111 deletions(-) create mode 100755 .github/qualification-ledger.sh create mode 100644 .github/workflows/certify-uk-release.yaml create mode 100644 changelog.d/573.added.md create mode 100644 scripts/check_uk_candidate.py create mode 100644 scripts/release_consumers.py create mode 100644 src/policyengine/data/qualification/uk_budget_critical_inputs.json create mode 100644 src/policyengine/data/qualification/uk_review_bounds.json create mode 100644 src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md create mode 100644 src/policyengine/provenance/qualification_ledger.py create mode 100644 src/policyengine/provenance/uk_candidate.py create mode 100644 src/policyengine/provenance/uk_qualification.py create mode 100644 tests/qualification_fixtures.py create mode 100644 tests/test_qualification_contracts.py create mode 100644 tests/test_qualified_pair_certification.py create mode 100644 tests/test_uk_candidate_gates.py create mode 100644 tests/test_uk_qualification_pipeline.py diff --git a/.github/dispatch-policyengine-release.sh b/.github/dispatch-policyengine-release.sh index fa2b3579..b41f22e0 100755 --- a/.github/dispatch-policyengine-release.sh +++ b/.github/dispatch-policyengine-release.sh @@ -1,13 +1,19 @@ #!/usr/bin/env bash # # Notify consumer repositories that a policyengine release is available on -# PyPI by sending a policyengine-release repository dispatch, which triggers -# their update workflows to open single-version bump PRs. +# PyPI by sending a repository dispatch, which triggers their update +# workflows. # # Environment: -# VERSION Exact policyengine version that was released. -# GH_TOKEN PolicyEngine GitHub App token with Contents write access to the -# consumer repositories. +# VERSION Exact policyengine version that was released. +# GH_TOKEN PolicyEngine GitHub App token with Contents write access to +# the consumer repositories. +# CONSUMER_REPOS Space-separated repositories to notify (default: +# policyengine-api policyengine-sim-api). +# PAYLOAD_FILE Optional JSON file holding the whole dispatch body +# ({"event_type": ..., "client_payload": {...}}), as written +# by scripts/release_consumers.py. Without it, a +# policyengine-release event carrying only the version is sent. set -euo pipefail if [[ -z "${VERSION:-}" ]]; then @@ -15,14 +21,31 @@ if [[ -z "${VERSION:-}" ]]; then exit 1 fi -CONSUMER_REPOS=( - policyengine-api - policyengine-sim-api +read -r -a REPOS <<< "${CONSUMER_REPOS:-policyengine-api policyengine-sim-api}" + +if [[ -n "${PAYLOAD_FILE:-}" ]]; then + payload_version=$(python - "$PAYLOAD_FILE" <<'PY' +import json +import sys + +payload = json.load(open(sys.argv[1]))["client_payload"] +request = payload.get("request") +print(payload.get("version") or request["candidate"]["policyengine"]["version"]) +PY ) + if [[ "$payload_version" != "$VERSION" ]]; then + echo "ERROR: ${PAYLOAD_FILE} is for ${payload_version}, not ${VERSION}." >&2 + exit 1 + fi +fi -for repo in "${CONSUMER_REPOS[@]}"; do - gh api "repos/PolicyEngine/${repo}/dispatches" \ - -f event_type=policyengine-release \ - -f "client_payload[version]=${VERSION}" - echo "Dispatched policyengine-release ${VERSION} to PolicyEngine/${repo}." +for repo in "${REPOS[@]}"; do + if [[ -n "${PAYLOAD_FILE:-}" ]]; then + gh api "repos/PolicyEngine/${repo}/dispatches" --method POST --input "$PAYLOAD_FILE" + else + gh api "repos/PolicyEngine/${repo}/dispatches" \ + -f event_type=policyengine-release \ + -f "client_payload[version]=${VERSION}" + fi + echo "Dispatched policyengine ${VERSION} to PolicyEngine/${repo}." done diff --git a/.github/qualification-ledger.sh b/.github/qualification-ledger.sh new file mode 100755 index 00000000..6a1bff7c --- /dev/null +++ b/.github/qualification-ledger.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +# +# Check out, or publish to, the qualification ledger branch. +# +# .github/qualification-ledger.sh checkout +# .github/qualification-ledger.sh publish "" +# +# The ledger is an orphan branch that only grows: each candidate pair writes +# its own directory, so concurrent publishes never touch the same file and a +# rejected push is retried by replaying the single new commit on the latest +# tip. +set -euo pipefail + +BRANCH="${LEDGER_BRANCH:-uk-qualification-ledger}" +command="${1:?usage: qualification-ledger.sh checkout|publish [message]}" +dir="${2:?ledger directory required}" + +case "$command" in + checkout) + if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then + git fetch --quiet origin "$BRANCH" + git worktree add --quiet --force -B "$BRANCH" "$dir" FETCH_HEAD + else + git worktree add --quiet --detach "$dir" + ( + cd "$dir" + git switch --quiet --orphan "$BRANCH" + cat > README.md <<'README' +# UK candidate qualification ledger + +Written by `.github/workflows/certify-uk-release.yaml` in PolicyEngine/policyengine.py. +Each `uk//` directory holds a candidate pair, every qualification +attempt's gate evidence, the replay request and receipt, and the latest +qualification receipt. Nothing is deleted. +README + ) + fi + ;; + publish) + message="${3:?commit message required}" + cd "$dir" + git add -A + if git diff --cached --quiet; then + echo "Ledger unchanged." + exit 0 + fi + git -c user.name="policyengine-qualification[bot]" \ + -c user.email="qualification@policyengine.org" \ + commit --quiet -m "$message" + for attempt in 1 2 3 4 5 6; do + if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then + echo "Published ledger: $message" + exit 0 + fi + git fetch --quiet origin "$BRANCH" + git rebase --quiet --onto FETCH_HEAD HEAD~1 HEAD + sleep $((attempt * 5)) + done + echo "::error::Could not publish the qualification ledger after 6 attempts." + exit 1 + ;; + *) + echo "Unknown command: $command" >&2 + exit 2 + ;; +esac diff --git a/.github/workflows/certify-uk-release.yaml b/.github/workflows/certify-uk-release.yaml new file mode 100644 index 00000000..6940cd45 --- /dev/null +++ b/.github/workflows/certify-uk-release.yaml @@ -0,0 +1,418 @@ +# Qualify each new policyengine-uk wheel or uk-data release before promotion. +# +# A candidate pair (newest model wheel, the core it needs, newest data +# release) is resolved and deduplicated against the ledger, certified into a +# candidate commit on candidate/uk/- (manifest, pins, uv.lock, +# TRO, test constants and snapshots regenerated together), qualified by the +# mandatory gates on that exact commit, replayed by policyengine-scorecard, +# and recorded in the uk-qualification-ledger branch. Promotion is +# serialized: it readies the newest promotable candidate PR that advances +# main and closes superseded ones. Merging stays a reviewed step until +# cos d1344 rules on automatic promotion. +# +# Triggers: a policyengine-uk publish or uk-data release (repository +# dispatch), a two-hourly catch-up, or a manual run. A manual run with +# accept_pair_id records a reviewer's acceptance of a needs-review receipt. + +name: Certify UK release candidates + +on: + repository_dispatch: + types: [policyengine-uk-release, policyengine-uk-data-release] + schedule: + - cron: "23 */2 * * *" + workflow_dispatch: + inputs: + model_version: + description: policyengine-uk version (default newest on PyPI) + required: false + data_version: + description: uk-data release (default newest) + required: false + force: + description: Qualify even if the ledger already has a terminal receipt + type: boolean + default: false + accept_pair_id: + description: Accept the needs-review receipt of this pair (reviewer = you) + required: false + accept_receipt_sha256: + description: unreviewed_sha256 of the exact receipt being accepted + required: false + accept_explanation: + description: Why the flagged moves are expected + required: false + +permissions: + contents: write + pull-requests: write + +env: + LEDGER_BRANCH: uk-qualification-ledger + UV_VERSION: "0.12.14" + PYTHON_VERSION: "3.13" + +jobs: + resolve: + if: github.event_name != 'workflow_dispatch' || inputs.accept_pair_id == '' + runs-on: ubuntu-latest + timeout-minutes: 20 + outputs: + action: ${{ steps.resolve.outputs.action }} + pair_id: ${{ steps.resolve.outputs.pair_id }} + branch: ${{ steps.resolve.outputs.branch }} + base_commit: ${{ steps.resolve.outputs.base_commit }} + attempt_key: ${{ steps.resolve.outputs.attempt_key }} + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install policyengine without country models + run: uv pip install --system -e . + - name: Check out the ledger + run: .github/qualification-ledger.sh checkout ledger + - name: Resolve and deduplicate the candidate + id: resolve + env: + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + EVENT_NAME: ${{ github.event_name }} + EVENT_TYPE: ${{ github.event.action }} + PAYLOAD_VERSION: ${{ github.event.client_payload.version }} + INPUT_MODEL: ${{ inputs.model_version }} + INPUT_DATA: ${{ inputs.data_version }} + INPUT_FORCE: ${{ inputs.force }} + run: | + model="${INPUT_MODEL:-}" + data="${INPUT_DATA:-}" + if [[ "$EVENT_NAME" == "repository_dispatch" && "$EVENT_TYPE" == "policyengine-uk-release" ]]; then + model="$PAYLOAD_VERSION" + elif [[ "$EVENT_NAME" == "repository_dispatch" && "$EVENT_TYPE" == "policyengine-uk-data-release" ]]; then + data="$PAYLOAD_VERSION" + fi + args=(resolve --out candidate.json --ledger ledger) + [[ -n "$model" ]] && args+=(--model-version "$model") + [[ -n "$data" ]] && args+=(--data-version "$data") + [[ "${INPUT_FORCE:-false}" == "true" ]] && args+=(--force) + python scripts/check_uk_candidate.py "${args[@]}" + - uses: actions/upload-artifact@v4 + with: + name: candidate + path: candidate.json + + prepare: + needs: resolve + if: needs.resolve.outputs.action == 'qualify' + runs-on: ubuntu-latest + timeout-minutes: 60 + concurrency: + group: uk-candidate-${{ needs.resolve.outputs.pair_id }} + cancel-in-progress: false + outputs: + candidate_commit: ${{ steps.stage.outputs.candidate_commit }} + duplicate: ${{ steps.duplicate.outputs.duplicate }} + steps: + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - uses: actions/checkout@v6 + with: + ref: ${{ needs.resolve.outputs.base_commit }} + token: ${{ steps.app-token.outputs.token }} + fetch-depth: 0 + # Another run may have staged this attempt while this one waited for + # the pair's concurrency group; never overwrite its evidence. + - name: Check for an attempt staged by another run + id: duplicate + env: + ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }} + run: | + .github/qualification-ledger.sh checkout ledger + if [[ -d "$ATTEMPT" ]]; then + echo "duplicate=true" >> "$GITHUB_OUTPUT" + echo "Attempt already staged by another run; nothing to do." + else + echo "duplicate=false" >> "$GITHUB_OUTPUT" + fi + git worktree remove --force ledger + - uses: actions/download-artifact@v4 + if: steps.duplicate.outputs.duplicate == 'false' + with: + name: candidate + path: ${{ runner.temp }}/candidate + - uses: astral-sh/setup-uv@v8.1.0 + if: steps.duplicate.outputs.duplicate == 'false' + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + if: steps.duplicate.outputs.duplicate == 'false' + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install the base environment + if: steps.duplicate.outputs.duplicate == 'false' + run: uv sync --frozen --extra uk --extra dev --python ${{ env.PYTHON_VERSION }} + - name: Certify the pair and regenerate pins, lock, TROs and constants + if: steps.duplicate.outputs.duplicate == 'false' + env: + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + BRANCH: ${{ needs.resolve.outputs.branch }} + run: | + git switch -C "$BRANCH" + uv run python scripts/check_uk_candidate.py prepare \ + --candidate "$RUNNER_TEMP/candidate/candidate.json" \ + --out "$RUNNER_TEMP/prepared.json" --skip-snapshots + - name: Install the candidate environment from the regenerated lock + if: steps.duplicate.outputs.duplicate == 'false' + run: uv sync --frozen --extra uk --extra dev --python ${{ env.PYTHON_VERSION }} + - name: Refresh household snapshots on the candidate pair + if: steps.duplicate.outputs.duplicate == 'false' + env: + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + PE_UPDATE_SNAPSHOTS: "1" + run: uv run pytest tests/test_household_calculator_snapshot.py -q + - name: Check the regenerated bundle + if: steps.duplicate.outputs.duplicate == 'false' + env: + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + run: uv run python scripts/bundle.py check --include-tros --strict-tros + - name: Commit and push the candidate commit + if: steps.duplicate.outputs.duplicate == 'false' + env: + BRANCH: ${{ needs.resolve.outputs.branch }} + PAIR_ID: ${{ needs.resolve.outputs.pair_id }} + run: | + git add -A + git -c user.name="policyengine-qualification[bot]" \ + -c user.email="qualification@policyengine.org" \ + commit -q -m "Certify UK candidate pair ${PAIR_ID:0:12} for qualification" + git push --force origin "HEAD:refs/heads/$BRANCH" + - name: Stage the attempt in the ledger + id: stage + if: steps.duplicate.outputs.duplicate == 'false' + run: | + .github/qualification-ledger.sh checkout ledger + uv run python scripts/check_uk_candidate.py stage \ + --candidate "$RUNNER_TEMP/candidate/candidate.json" --ledger ledger + .github/qualification-ledger.sh publish ledger \ + "Stage UK candidate ${{ needs.resolve.outputs.pair_id }} attempt ${{ needs.resolve.outputs.attempt_key }}" + - name: Open or update the draft candidate PR + if: steps.duplicate.outputs.duplicate == 'false' + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + BRANCH: ${{ needs.resolve.outputs.branch }} + PAIR_ID: ${{ needs.resolve.outputs.pair_id }} + run: | + title="Certify UK candidate ${BRANCH#candidate/uk/}" + body="Automated certification candidate for pair \`$PAIR_ID\`. Qualification is running: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} + + Ledger: https://github.com/${GITHUB_REPOSITORY}/tree/${LEDGER_BRANCH}/uk/${PAIR_ID} + + 🤖 Generated with [Claude Code](https://claude.com/claude-code)" + if gh pr view "$BRANCH" --json number >/dev/null 2>&1; then + gh pr edit "$BRANCH" --body "$body" + else + gh pr create --draft --base main --head "$BRANCH" --title "$title" --body "$body" + fi + + qualify: + needs: [resolve, prepare] + if: needs.prepare.outputs.duplicate == 'false' + runs-on: ubuntu-latest + timeout-minutes: 120 + concurrency: + group: uk-candidate-${{ needs.resolve.outputs.pair_id }} + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + with: + ref: ${{ needs.prepare.outputs.candidate_commit }} + fetch-depth: 0 + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install the candidate environment + run: uv sync --frozen --extra uk --extra dev --python ${{ env.PYTHON_VERSION }} + - name: Check out the ledger + run: .github/qualification-ledger.sh checkout ledger + - name: Run the mandatory local gates + env: + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }} + run: uv run python scripts/check_uk_candidate.py gates --attempt "$ATTEMPT" --work-dir "$RUNNER_TEMP/qualification" + - name: Generate a GitHub App token for the scorecard + id: scorecard-token + continue-on-error: true + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: PolicyEngine + repositories: policyengine-scorecard + - name: Send the pre-promotion replay request + if: steps.scorecard-token.outcome == 'success' + continue-on-error: true + env: + GH_TOKEN: ${{ steps.scorecard-token.outputs.token }} + ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }} + run: uv run python scripts/check_uk_candidate.py request-replay --attempt "$ATTEMPT" --dispatch + - name: Publish the gate evidence + if: always() + run: | + .github/qualification-ledger.sh publish ledger \ + "Gates for UK candidate ${{ needs.resolve.outputs.pair_id }} attempt ${{ needs.resolve.outputs.attempt_key }}" + + replay: + needs: [resolve, prepare, qualify] + if: always() && needs.prepare.result == 'success' && needs.prepare.outputs.duplicate == 'false' + runs-on: ubuntu-latest + timeout-minutes: 355 + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install policyengine without country models + run: uv pip install --system -e . + - name: Check out the ledger + run: .github/qualification-ledger.sh checkout ledger + - name: Wait for the replay receipt + env: + GH_TOKEN: ${{ github.token }} + ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }} + run: | + if [[ -f "$ATTEMPT/replay/request.json" ]]; then + python scripts/check_uk_candidate.py poll-replay --attempt "$ATTEMPT" --wait-minutes 340 + else + echo "No replay request was sent; the replay gate stays unavailable." + fi + - name: Finalize and publish the qualification receipt + id: finalize + env: + ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }} + run: | + python scripts/check_uk_candidate.py finalize --attempt "$ATTEMPT" --ledger ledger --pr-body "$RUNNER_TEMP/pr-body.md" + .github/qualification-ledger.sh publish ledger \ + "Qualification receipt for UK candidate ${{ needs.resolve.outputs.pair_id }}" + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Update the candidate PR with the verdict + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + BRANCH: ${{ needs.resolve.outputs.branch }} + run: gh pr edit "$BRANCH" --body-file "$RUNNER_TEMP/pr-body.md" + + catch-up: + if: github.event_name == 'schedule' + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install policyengine without country models + run: uv pip install --system -e . + - name: Finish attempts whose replay outlasted their run + env: + GH_TOKEN: ${{ github.token }} + run: | + .github/qualification-ledger.sh checkout ledger + python scripts/check_uk_candidate.py waiting --ledger ledger > waiting.txt + while read -r attempt; do + [[ -z "$attempt" ]] && continue + python scripts/check_uk_candidate.py poll-replay --attempt "$attempt" + python scripts/check_uk_candidate.py finalize --attempt "$attempt" --ledger ledger + done < waiting.txt + .github/qualification-ledger.sh publish ledger "Catch up waiting UK replay receipts" + + accept: + if: github.event_name == 'workflow_dispatch' && inputs.accept_pair_id != '' + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - name: Install policyengine without country models + run: uv pip install --system -e . + - name: Record the reviewer's acceptance + env: + PAIR_ID: ${{ inputs.accept_pair_id }} + RECEIPT: ${{ inputs.accept_receipt_sha256 }} + EXPLANATION: ${{ inputs.accept_explanation }} + REVIEWER: ${{ github.actor }} + run: | + .github/qualification-ledger.sh checkout ledger + python scripts/check_uk_candidate.py accept --ledger ledger \ + --pair-id "$PAIR_ID" --receipt-sha256 "$RECEIPT" \ + --explanation "$EXPLANATION" --reviewer "$REVIEWER" + .github/qualification-ledger.sh publish ledger "Accept UK candidate $PAIR_ID on review by $REVIEWER" + + promote: + needs: [resolve, replay, catch-up, accept] + if: always() + runs-on: ubuntu-latest + timeout-minutes: 15 + concurrency: + group: promote-uk + cancel-in-progress: false + steps: + - uses: actions/checkout@v6 + with: + ref: main + fetch-depth: 0 + - uses: astral-sh/setup-uv@v8.1.0 + with: + version: ${{ env.UV_VERSION }} + - uses: actions/setup-python@v6 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install policyengine without country models + run: uv pip install --system -e . + - name: Generate GitHub App token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + - name: Promote the newest qualified pair that advances main + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + .github/qualification-ledger.sh checkout ledger + python scripts/check_uk_candidate.py promote --ledger ledger --apply diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml index 6328c266..0d634c30 100644 --- a/.github/workflows/push.yaml +++ b/.github/workflows/push.yaml @@ -7,8 +7,11 @@ # Phase 2 (sentinel commit): Publish to PyPI + GitHub Release # Skips Lint + Test since the code is identical to Phase 1. # After Publish, NotifyConsumers waits for the release to be visible on -# PyPI and sends a policyengine-release repository dispatch to consumer -# repos so they open version-bump PRs. +# PyPI and sends a policyengine-release repository dispatch (version plus +# the certified UK bundle identity and qualification digests) to consumer +# repos so they open version-bump PRs, then a released-bundle replay +# request to policyengine-scorecard. New consumers are dispatched in +# separate, non-blocking steps. name: Push to main @@ -247,6 +250,19 @@ jobs: run: bash .github/wait-for-pypi.sh - name: Validate published SPM bundle before consumer updates run: python -S scripts/bundle.py check --published-spm + - name: Install uv + uses: astral-sh/setup-uv@v8.1.0 + with: + version: "0.12.14" + - name: Install policyengine without country models + run: uv pip install -e . --system + # The payload carries the certified UK bundle identity and, for an + # automatically qualified pair, the qualification receipt digest. + # client_payload.version stays first, as existing updaters read only it. + - name: Build the release dispatch payload + env: + VERSION: ${{ needs.Publish.outputs.version }} + run: python scripts/release_consumers.py payload --version "$VERSION" > "$RUNNER_TEMP/release-payload.json" - name: Generate GitHub App token id: app-token uses: actions/create-github-app-token@v1 @@ -259,4 +275,58 @@ jobs: env: GH_TOKEN: ${{ steps.app-token.outputs.token }} VERSION: ${{ needs.Publish.outputs.version }} + PAYLOAD_FILE: ${{ runner.temp }}/release-payload.json + run: bash .github/dispatch-policyengine-release.sh + # New consumers are dispatched separately, so a missing App + # installation on one of them can never block the consumers above. + - name: Generate GitHub App token for the Budget dashboard + id: dashboard-token + continue-on-error: true + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: PolicyEngine + repositories: uk-autumn-budget-dashboard-2026 + - name: Dispatch policyengine-release to the Budget dashboard + if: steps.dashboard-token.outcome == 'success' + continue-on-error: true + env: + GH_TOKEN: ${{ steps.dashboard-token.outputs.token }} + VERSION: ${{ needs.Publish.outputs.version }} + PAYLOAD_FILE: ${{ runner.temp }}/release-payload.json + CONSUMER_REPOS: uk-autumn-budget-dashboard-2026 + run: bash .github/dispatch-policyengine-release.sh + - name: Install the released bundle for the replay request + continue-on-error: true + id: released + env: + VERSION: ${{ needs.Publish.outputs.version }} + run: uv pip install --system "policyengine[uk]==$VERSION" + - name: Build the scorecard's released-bundle replay request + if: steps.released.outcome == 'success' + id: scorecard-request + continue-on-error: true + env: + VERSION: ${{ needs.Publish.outputs.version }} + HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }} + run: python scripts/release_consumers.py scorecard-request --version "$VERSION" > "$RUNNER_TEMP/scorecard-request.json" + - name: Generate GitHub App token for the scorecard + if: steps.scorecard-request.outcome == 'success' + id: scorecard-token + continue-on-error: true + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + owner: PolicyEngine + repositories: policyengine-scorecard + - name: Send the scorecard a released-bundle replay request + if: steps.scorecard-token.outcome == 'success' + continue-on-error: true + env: + GH_TOKEN: ${{ steps.scorecard-token.outputs.token }} + VERSION: ${{ needs.Publish.outputs.version }} + PAYLOAD_FILE: ${{ runner.temp }}/scorecard-request.json + CONSUMER_REPOS: policyengine-scorecard run: bash .github/dispatch-policyengine-release.sh diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md new file mode 100644 index 00000000..73c9d238 --- /dev/null +++ b/changelog.d/573.added.md @@ -0,0 +1 @@ +Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well. diff --git a/scripts/bundle.py b/scripts/bundle.py index 121ab8e2..072b2cb3 100644 --- a/scripts/bundle.py +++ b/scripts/bundle.py @@ -50,6 +50,10 @@ def _certify_data(args: argparse.Namespace) -> int: argv.append("--no-changelog") if args.skip_artifact_check: argv.append("--skip-artifact-check") + if args.core_version: + argv.extend(["--core-version", args.core_version]) + if args.qualified_pair_id: + argv.extend(["--qualified-pair-id", args.qualified_pair_id]) return certify_data_release_main(argv) @@ -226,6 +230,14 @@ def _parser() -> argparse.ArgumentParser: "vendored/regional artifacts." ), ) + certify.add_argument( + "--core-version", + help="policyengine-core version to check against core claims and pin.", + ) + certify.add_argument( + "--qualified-pair-id", + help="Admit the exact pair on automated qualification (needs --core-version).", + ) certify.set_defaults(func=_certify_data) packages = subparsers.add_parser( diff --git a/scripts/certify_data_release.py b/scripts/certify_data_release.py index 8842adbb..7a55ca2f 100644 --- a/scripts/certify_data_release.py +++ b/scripts/certify_data_release.py @@ -72,6 +72,22 @@ def main(argv=None) -> int: default=None, help="Model package version to certify for (default: installed).", ) + parser.add_argument( + "--core-version", + default=None, + help=( + "policyengine-core version to check against the release's core " + "claims and pin in the bundle." + ), + ) + parser.add_argument( + "--qualified-pair-id", + default=None, + help=( + "Admit the exact model, core and data release on automated " + "qualification of this pair (requires --core-version)." + ), + ) parser.add_argument("--no-generate", action="store_true") parser.add_argument("--no-changelog", action="store_true") parser.add_argument( @@ -102,6 +118,8 @@ def main(argv=None) -> int: regional_manifest_uri=args.regional_manifest_uri, regional_artifact_prefix=args.regional_artifact_prefix, regional_path_template=args.regional_path_template, + core_version=args.core_version, + qualified_pair_id=args.qualified_pair_id, ) print(result.summary()) diff --git a/scripts/check_uk_candidate.py b/scripts/check_uk_candidate.py new file mode 100644 index 00000000..000b4237 --- /dev/null +++ b/scripts/check_uk_candidate.py @@ -0,0 +1,572 @@ +"""Qualify a UK model/data candidate before it can be promoted. + +Run by ``.github/workflows/certify-uk-release.yaml``; every step also runs +locally. Network access: PyPI, Hugging Face (``HUGGING_FACE_TOKEN``) and, for +the replay and promotion steps, GitHub (``GH_TOKEN``). + +Each attempt lives in one ledger directory, ``/uk//attempts/ +/``, which every step after ``resolve`` reads and writes:: + + python scripts/check_uk_candidate.py resolve --out candidate.json \\ + [--model-version 2.126.8] [--data-version 1.58.0] [--ledger ledger/] [--force] + python scripts/check_uk_candidate.py prepare --candidate candidate.json --skip-snapshots + python scripts/check_uk_candidate.py stage --candidate candidate.json --ledger ledger/ + python scripts/check_uk_candidate.py gates --attempt + python scripts/check_uk_candidate.py request-replay --attempt [--dispatch] + python scripts/check_uk_candidate.py poll-replay --attempt [--wait-minutes 340] + python scripts/check_uk_candidate.py finalize --attempt --ledger ledger/ + python scripts/check_uk_candidate.py waiting --ledger ledger/ + python scripts/check_uk_candidate.py promote --ledger ledger/ [--apply] + python scripts/check_uk_candidate.py accept --ledger ledger/ --pair-id ... \\ + --receipt-sha256 ... --explanation "..." [--reviewer login] + +Steps that the workflow branches on also write ``key=value`` lines to +``$GITHUB_OUTPUT`` when it is set. +""" + +from __future__ import annotations + +import argparse +import datetime +import json +import os +import subprocess +import sys +import time +from pathlib import Path +from typing import Any, Optional + +REPO_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(REPO_ROOT / "src")) +os.environ.setdefault("POLICYENGINE_SKIP_COUNTRY_IMPORTS", "1") + +import requests # noqa: E402 + +from policyengine.provenance.qualification import ( # noqa: E402 + CandidatePair, + IssuedBy, + QualificationHarness, + QualificationReceipt, + ReplayQualificationRequest, +) +from policyengine.provenance.qualification_ledger import ( # noqa: E402 + LEDGER_BRANCH, + LEDGER_REPOSITORY, + attempt_directory, + latest_receipts, + pair_directory, + read_json, + write_json, +) +from policyengine.provenance.uk_qualification import ( # noqa: E402 + ResolvedCandidate, + WheelFile, + accept_review, + attempt_is_waiting_for_replay, + build_replay_request, + candidate_action, + candidate_branch, + candidate_pr_body, + expected_release_bundle, + finalize_attempt, + packaged_manifest_sha256, + plan_promotion, + prepare_candidate_commit, + previous_certificate, + read_replay, + replay_dispatch_payload, + resolve_candidate, + stage_attempt, + write_gate_results, +) + +BUNDLE_PATH = REPO_ROOT / "src" / "policyengine" / "data" / "bundle" / "manifest.json" +CONFIG_PATH = REPO_ROOT / "src" / "policyengine" / "data" / "qualification" / "uk.json" +TIMEOUT = 60 + + +def utc_now() -> str: + return datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%dT%H:%M:%SZ") + + +def config() -> dict[str, Any]: + return json.loads(CONFIG_PATH.read_text()) + + +def hf_headers() -> dict[str, str]: + token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN") + return {"Authorization": f"Bearer {token}"} if token else {} + + +def pypi_project(path: str) -> dict[str, Any]: + response = requests.get(f"https://pypi.org/pypi/{path}/json", timeout=TIMEOUT) + response.raise_for_status() + return response.json() + + +def hf_revision_sha(repo_id: str, revision: str) -> str: + response = requests.get( + f"https://huggingface.co/api/models/{repo_id}/revision/{revision}", + headers=hf_headers(), + timeout=TIMEOUT, + ) + response.raise_for_status() + return str(response.json()["sha"]) + + +def hf_tags(repo_id: str) -> list[str]: + response = requests.get( + f"https://huggingface.co/api/models/{repo_id}/refs", + headers=hf_headers(), + timeout=TIMEOUT, + ) + response.raise_for_status() + return [tag["name"] for tag in response.json().get("tags", [])] + + +def hf_file(repo_id: str, revision: str, path: str) -> bytes: + response = requests.get( + f"https://huggingface.co/{repo_id}/resolve/{revision}/{path}", + headers=hf_headers(), + timeout=TIMEOUT, + ) + response.raise_for_status() + return response.content + + +def scorecard_file(repository: str): + token = os.environ.get("GH_TOKEN") or os.environ.get("GITHUB_TOKEN") + headers = {"Accept": "application/vnd.github.raw+json"} + if token: + headers["Authorization"] = f"Bearer {token}" + + def fetch(ref: str, path: str) -> Optional[bytes]: + response = requests.get( + f"https://api.github.com/repos/{repository}/contents/{path}", + params={"ref": ref}, + headers=headers, + timeout=TIMEOUT, + ) + if response.status_code == 404: + return None + response.raise_for_status() + return response.content + + return fetch + + +def issued_by() -> IssuedBy: + server = os.environ.get("GITHUB_SERVER_URL", "https://github.com") + repository = os.environ.get("GITHUB_REPOSITORY", LEDGER_REPOSITORY) + run_id = int(os.environ.get("GITHUB_RUN_ID", "1")) + return IssuedBy( + repository=repository, + workflow_run_id=run_id, + run_attempt=int(os.environ.get("GITHUB_RUN_ATTEMPT", "1")), + run_url=f"{server}/{repository}/actions/runs/{run_id}", + ) + + +def git(*args: str, cwd: Path = REPO_ROOT) -> str: + return subprocess.run( + ["git", *args], cwd=cwd, check=True, capture_output=True, text=True + ).stdout.strip() + + +def set_output(**values: str) -> None: + path = os.environ.get("GITHUB_OUTPUT") + if not path: + return + with open(path, "a") as stream: + for key, value in values.items(): + stream.write(f"{key}={value}\n") + + +def resolved_from(payload: dict[str, Any]) -> ResolvedCandidate: + return ResolvedCandidate( + pair=CandidatePair.model_validate(payload["pair"]), + model_wheel=WheelFile(**payload["model_wheel"]), + core_wheel=WheelFile(**payload["core_wheel"]), + manifest_uri=payload["manifest_uri"], + model_requires_core=payload["model_requires_core"], + ) + + +def ledger_url(pair_id: str) -> str: + return f"https://github.com/{LEDGER_REPOSITORY}/tree/{LEDGER_BRANCH}/uk/{pair_id}" + + +# --- Commands ----------------------------------------------------------------- + + +def cmd_resolve(args: argparse.Namespace) -> int: + bundle = json.loads(BUNDLE_PATH.read_text()) + resolved = resolve_candidate( + current_core=bundle["packages"]["policyengine-core"]["version"], + pypi_project=pypi_project, + hf_revision_sha=hf_revision_sha, + hf_tags=hf_tags, + hf_file=hf_file, + model_version=args.model_version or None, + data_version=args.data_version or None, + ) + base_commit = git("rev-parse", "HEAD") + action, reason = candidate_action( + resolved.pair, + bundle, + Path(args.ledger) if args.ledger else None, + base_commit=base_commit, + force=args.force, + ) + payload = { + "pair": resolved.pair.canonical_payload(), + "pair_id": resolved.pair.pair_id, + "model_wheel": resolved.model_wheel.__dict__, + "core_wheel": resolved.core_wheel.__dict__, + "manifest_uri": resolved.manifest_uri, + "model_requires_core": resolved.model_requires_core, + "base_commit": base_commit, + "attempt_key": base_commit[:12], + "branch": candidate_branch(resolved.pair), + "action": action, + "reason": reason, + "previous_certificate": previous_certificate(bundle).canonical_payload(), + } + write_json(Path(args.out), payload) + print( + f"{action}: {reason} (pair {resolved.pair.pair_id[:12]}, {resolved.pair.order_key})" + ) + set_output( + action=action, + pair_id=resolved.pair.pair_id, + branch=candidate_branch(resolved.pair), + base_commit=base_commit, + attempt_key=base_commit[:12], + ) + return 0 + + +def cmd_prepare(args: argparse.Namespace) -> int: + payload = json.loads(Path(args.candidate).read_text()) + prepared = prepare_candidate_commit( + REPO_ROOT, + resolved_from(payload), + python=sys.executable, + refresh_snapshots=not args.skip_snapshots, + ) + write_json(Path(args.out), prepared) + print(json.dumps(prepared, indent=2)) + return 0 + + +def cmd_stage(args: argparse.Namespace) -> int: + from importlib.metadata import version + + payload = json.loads(Path(args.candidate).read_text()) + harness = QualificationHarness( + policyengine_version=version("policyengine"), + git_commit=git("rev-parse", "HEAD"), + packaged_bundle_manifest_sha256=packaged_manifest_sha256(REPO_ROOT), + ) + attempt = attempt_directory( + Path(args.ledger), "uk", payload["pair_id"], payload["attempt_key"] + ) + stage_attempt(attempt, payload, harness) + print(f"staged {attempt} at {harness.git_commit}") + set_output(attempt=str(attempt), candidate_commit=harness.git_commit) + return 0 + + +def _attempt( + args: argparse.Namespace, +) -> tuple[Path, dict[str, Any], QualificationHarness]: + attempt = Path(args.attempt) + payload = read_json(attempt / "candidate.json") + harness = QualificationHarness.model_validate(read_json(attempt / "harness.json")) + return attempt, payload, harness + + +def cmd_gates(args: argparse.Namespace) -> int: + from policyengine.provenance import uk_candidate + + attempt, payload, harness = _attempt(args) + if git("rev-parse", "HEAD") != harness.git_commit: + raise SystemExit( + "Gates must run on the candidate commit named in harness.json." + ) + ledger_root = attempt.parents[3] + results, evidence = uk_candidate.run_candidate_gates( + resolved_from(payload), + harness, + config=config(), + work_dir=Path(args.work_dir), + previous_certificate=payload.get("previous_certificate"), + ledger_root=ledger_root, + ) + write_gate_results(attempt, results, evidence) + for result in results: + print(f"{result.gate_id:20s} {result.status:13s} {result.summary}") + return 0 + + +def cmd_request_replay(args: argparse.Namespace) -> int: + attempt, payload, harness = _attempt(args) + request = build_replay_request( + CandidatePair.model_validate(payload["pair"]), + harness, + release_bundle=expected_release_bundle(sys.executable, cwd=REPO_ROOT), + issued_by=issued_by(), + attempt=args.replay_attempt, + compare_to=config()["replay"]["compare_to"], + ) + print(f"request_id {request.request_id}") + if args.dispatch: + settings = config()["replay"] + subprocess.run( + [ + "gh", + "api", + f"repos/{settings['repository']}/dispatches", + "--method", + "POST", + "--input", + "-", + ], + input=json.dumps( + replay_dispatch_payload(request, event_type=settings["event_type"]) + ), + text=True, + check=True, + ) + print(f"dispatched {settings['event_type']} to {settings['repository']}") + # Recorded only once sent: an attempt with a request waits for its replay. + write_json(attempt / "replay" / "request.json", request.document()) + set_output(request_id=request.request_id) + return 0 + + +def cmd_poll_replay(args: argparse.Namespace) -> int: + attempt = Path(args.attempt) + settings = config()["replay"] + request = ReplayQualificationRequest.model_validate( + read_json(attempt / "replay" / "request.json") + ) + fetch = scorecard_file(settings["repository"]) + deadline = time.monotonic() + 60 * args.wait_minutes + while True: + gate, status, receipt = read_replay( + request, fetch=fetch, state_ref=settings["state_ref"] + ) + if (status is not None and status.terminal) or time.monotonic() >= deadline: + break + time.sleep(args.interval_seconds) + write_json(attempt / "replay" / "replay.result.json", gate.canonical_payload()) + if status is not None: + write_json(attempt / "replay" / "status.json", status.document()) + if receipt is not None: + write_json(attempt / "replay" / "receipt.json", receipt.document()) + terminal = status is not None and status.terminal + print(f"replay {gate.status}: {gate.summary}") + set_output(replay_terminal="true" if terminal else "false") + return 0 + + +def cmd_finalize(args: argparse.Namespace) -> int: + attempt = Path(args.attempt) + receipt = finalize_attempt( + attempt, Path(args.ledger), issued_by=issued_by(), completed_at=utc_now() + ) + payload = read_json(attempt / "candidate.json") + body = candidate_pr_body( + receipt, receipt.pair, ledger_url=ledger_url(receipt.pair_id) + ) + if args.pr_body: + Path(args.pr_body).write_text(body) + print(f"verdict {receipt.verdict}; receipt {receipt.receipt_sha256}") + set_output( + verdict=receipt.verdict, + receipt_sha256=receipt.receipt_sha256, + branch=payload["branch"], + ) + return 0 + + +def cmd_waiting(args: argparse.Namespace) -> int: + base = Path(args.ledger) / "uk" + waiting = sorted( + str(path) + for path in base.glob("*/attempts/*") + if path.is_dir() and attempt_is_waiting_for_replay(path) + ) + for path in waiting: + print(path) + set_output(waiting=json.dumps(waiting)) + return 0 + + +def _open_candidate_branches() -> list[str]: + listing = subprocess.run( + [ + "gh", + "pr", + "list", + "--repo", + LEDGER_REPOSITORY, + "--state", + "open", + "--search", + "head:candidate/uk/", + "--json", + "headRefName", + ], + check=True, + capture_output=True, + text=True, + ).stdout + return [item["headRefName"] for item in json.loads(listing)] + + +def cmd_promote(args: argparse.Namespace) -> int: + bundle = json.loads(BUNDLE_PATH.read_text()) + receipts = latest_receipts(Path(args.ledger)) + branches = _open_candidate_branches() if args.apply else [] + plan = plan_promotion(receipts, bundle, branches) + print(f"promotion: {plan.reason}") + if plan.target is not None: + print(f"target {plan.ready_branch} (pair {plan.target.pair_id[:12]})") + for branch in plan.close_branches: + print(f"superseded {branch}") + if not args.apply: + return 0 + for branch in plan.close_branches: + subprocess.run( + [ + "gh", + "pr", + "close", + branch, + "--repo", + LEDGER_REPOSITORY, + "--comment", + f"Superseded: {plan.reason}. The ledger keeps this candidate's evidence.", + ], + check=False, + ) + if plan.ready_branch is not None and plan.ready_branch in branches: + subprocess.run( + ["gh", "pr", "ready", plan.ready_branch, "--repo", LEDGER_REPOSITORY], + check=False, + ) + if config()["promotion"]["automatic"]: + subprocess.run( + [ + "gh", + "pr", + "merge", + plan.ready_branch, + "--repo", + LEDGER_REPOSITORY, + "--auto", + "--squash", + ], + check=False, + ) + return 0 + + +def cmd_accept(args: argparse.Namespace) -> int: + path = ( + pair_directory(Path(args.ledger), "uk", args.pair_id) + / "qualification_receipt.json" + ) + receipt = QualificationReceipt.model_validate(read_json(path)) + reviewed = accept_review( + receipt, + reviewer=args.reviewer or os.environ.get("GITHUB_ACTOR", ""), + accepted_receipt_sha256=args.receipt_sha256, + explanation=args.explanation, + accepted_at=utc_now(), + ) + write_json(path, reviewed.canonical_payload()) + write_json( + path.parent / "reviews" / f"{reviewed.receipt_sha256}.json", + reviewed.canonical_payload(), + ) + print( + f"accepted {args.pair_id[:12]} by {reviewed.review.reviewer}; promotable={reviewed.promotable}" + ) + return 0 + + +def parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + commands = parser.add_subparsers(dest="command", required=True) + + resolve = commands.add_parser("resolve") + resolve.add_argument("--model-version") + resolve.add_argument("--data-version") + resolve.add_argument("--ledger") + resolve.add_argument("--force", action="store_true") + resolve.add_argument("--out", required=True) + resolve.set_defaults(func=cmd_resolve) + + prepare = commands.add_parser("prepare") + prepare.add_argument("--candidate", required=True) + prepare.add_argument("--out", default="prepared.json") + prepare.add_argument("--skip-snapshots", action="store_true") + prepare.set_defaults(func=cmd_prepare) + + stage = commands.add_parser("stage") + stage.add_argument("--candidate", required=True) + stage.add_argument("--ledger", required=True) + stage.set_defaults(func=cmd_stage) + + gates = commands.add_parser("gates") + gates.add_argument("--attempt", required=True) + gates.add_argument("--work-dir", default="qualification-work") + gates.set_defaults(func=cmd_gates) + + request = commands.add_parser("request-replay") + request.add_argument("--attempt", required=True) + request.add_argument("--replay-attempt", type=int, default=1) + request.add_argument("--dispatch", action="store_true") + request.set_defaults(func=cmd_request_replay) + + poll = commands.add_parser("poll-replay") + poll.add_argument("--attempt", required=True) + poll.add_argument("--wait-minutes", type=float, default=0) + poll.add_argument("--interval-seconds", type=float, default=300) + poll.set_defaults(func=cmd_poll_replay) + + finalize = commands.add_parser("finalize") + finalize.add_argument("--attempt", required=True) + finalize.add_argument("--ledger", required=True) + finalize.add_argument("--pr-body") + finalize.set_defaults(func=cmd_finalize) + + waiting = commands.add_parser("waiting") + waiting.add_argument("--ledger", required=True) + waiting.set_defaults(func=cmd_waiting) + + promote = commands.add_parser("promote") + promote.add_argument("--ledger", required=True) + promote.add_argument("--apply", action="store_true") + promote.set_defaults(func=cmd_promote) + + accept = commands.add_parser("accept") + accept.add_argument("--ledger", required=True) + accept.add_argument("--pair-id", required=True) + accept.add_argument("--receipt-sha256", required=True) + accept.add_argument("--explanation", required=True) + accept.add_argument("--reviewer") + accept.set_defaults(func=cmd_accept) + return parser + + +def main(argv: Optional[list[str]] = None) -> int: + args = parser().parse_args(argv) + return int(args.func(args) or 0) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/scripts/release_consumers.py b/scripts/release_consumers.py new file mode 100644 index 00000000..5e105cf4 --- /dev/null +++ b/scripts/release_consumers.py @@ -0,0 +1,162 @@ +"""Build the post-release dispatches for policyengine.py consumers. + +Run by the NotifyConsumers job in ``.github/workflows/push.yaml`` after a +release is visible on PyPI:: + + python scripts/release_consumers.py payload --version 6.2.7 > payload.json + python scripts/release_consumers.py scorecard-request --version 6.2.7 > request.json + +``payload`` is the ``policyengine-release`` repository dispatch (version, +certified UK bundle identity, qualification digests). ``scorecard-request`` +is the scorecard's ``released_bundle`` replay request; it needs the release +installed (``pip install "policyengine[uk]=="``) and +``HUGGING_FACE_TOKEN``. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import os +import subprocess +import sys +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(REPO_ROOT / "src")) +os.environ.setdefault("POLICYENGINE_SKIP_COUNTRY_IMPORTS", "1") + +import requests # noqa: E402 + +from policyengine.provenance.qualification_ledger import fetch_ledger_receipt # noqa: E402 +from policyengine.provenance.uk_qualification import ( # noqa: E402 + release_dispatch_payload, + released_bundle_request, +) + +BUNDLE_PATH = REPO_ROOT / "src" / "policyengine" / "data" / "bundle" / "manifest.json" +TIMEOUT = 60 +TOKEN_VARIABLES = ("HF_TOKEN", "HUGGING_FACE_TOKEN", "HUGGINGFACE_HUB_TOKEN") + + +def _bundle() -> dict: + return json.loads(BUNDLE_PATH.read_text()) + + +def _pypi(path: str) -> dict: + response = requests.get(f"https://pypi.org/pypi/{path}/json", timeout=TIMEOUT) + response.raise_for_status() + return response.json() + + +def _hf_file(repo_id: str, revision: str, path: str) -> bytes: + token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN") + response = requests.get( + f"https://huggingface.co/{repo_id}/resolve/{revision}/{path}", + headers={"Authorization": f"Bearer {token}"} if token else {}, + timeout=TIMEOUT, + ) + response.raise_for_status() + return response.content + + +def cmd_payload(args: argparse.Namespace) -> int: + payload = release_dispatch_payload( + _bundle(), version=args.version, fetch_receipt=fetch_ledger_receipt + ) + print(json.dumps(payload, sort_keys=True)) + return 0 + + +def _installed(code: str, *, strip_tokens: bool) -> str: + """Run ``code`` against the installed release, outside the checkout.""" + + env = dict(os.environ) + env.pop("POLICYENGINE_SKIP_COUNTRY_IMPORTS", None) + if strip_tokens: + for key in TOKEN_VARIABLES: + env.pop(key, None) + return subprocess.run( + [sys.executable, "-c", code], + env=env, + cwd="/", + check=True, + capture_output=True, + text=True, + ).stdout.strip() + + +def cmd_scorecard_request(args: argparse.Namespace) -> int: + release = _pypi(f"policyengine/{args.version}") + wheels = [item for item in release["urls"] if item["packagetype"] == "bdist_wheel"] + if len(wheels) != 1: + raise SystemExit(f"policyengine {args.version} must publish exactly one wheel.") + installed_version = _installed( + "from importlib.metadata import version; print(version('policyengine'))", + strip_tokens=False, + ) + if installed_version != args.version: + raise SystemExit( + f"policyengine {installed_version} is installed, not {args.version}." + ) + manifest_path = _installed( + "from importlib.resources import files; " + "print(files('policyengine').joinpath('data', 'bundle', 'manifest.json'))", + strip_tokens=False, + ) + release_bundle = json.loads( + _installed( + "import json, policyengine as pe; " + "print(json.dumps(dict(pe.uk.uk_latest.release_bundle), sort_keys=True))", + strip_tokens=True, + ).splitlines()[-1] + ) + server = os.environ.get("GITHUB_SERVER_URL", "https://github.com") + repository = os.environ.get("GITHUB_REPOSITORY", "PolicyEngine/policyengine.py") + run_id = os.environ.get("GITHUB_RUN_ID", "1") + request = released_bundle_request( + json.loads(Path(manifest_path).read_text()), + version=args.version, + wheel_sha256=wheels[0]["digests"]["sha256"], + packaged_manifest_sha256=hashlib.sha256( + Path(manifest_path).read_bytes() + ).hexdigest(), + release_bundle=release_bundle, + hf_file=_hf_file, + pypi_project=_pypi, + requested_by={ + "repository": repository, + "workflow_run_id": int(run_id), + "run_attempt": int(os.environ.get("GITHUB_RUN_ATTEMPT", "1")), + "commit": os.environ.get("GITHUB_SHA", "0" * 40), + "run_url": f"{server}/{repository}/actions/runs/{run_id}", + }, + ) + print( + json.dumps( + { + "event_type": "uk-replay-qualification-request", + "client_payload": {"request": request.document()}, + }, + sort_keys=True, + ) + ) + return 0 + + +def main(argv=None) -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + commands = parser.add_subparsers(dest="command", required=True) + payload = commands.add_parser("payload") + payload.add_argument("--version", required=True) + payload.set_defaults(func=cmd_payload) + scorecard = commands.add_parser("scorecard-request") + scorecard.add_argument("--version", required=True) + scorecard.set_defaults(func=cmd_scorecard_request) + args = parser.parse_args(argv) + return int(args.func(args) or 0) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json index 4e43592f..c0718585 100644 --- a/src/policyengine/data/qualification/uk.json +++ b/src/policyengine/data/qualification/uk.json @@ -9,8 +9,13 @@ "max_examples": 50 }, "metrics": { - "entrypoint": null, - "years": [2025, 2026, 2027, 2028, 2029, 2030], + "tool": { + "repository": "PolicyEngine/policyengine-uk", + "commit": "073e80809141852eda42127b9e692b17e81343eb", + "path": "policyengine_uk/utils/aggregate_impact", + "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands." + }, + "years": [2025, 2026, 2027, 2028, 2029, 2030, 2031], "bounds": "uk_review_bounds.json" }, "budget_inputs": { diff --git a/src/policyengine/data/qualification/uk_budget_critical_inputs.json b/src/policyengine/data/qualification/uk_budget_critical_inputs.json new file mode 100644 index 00000000..90d2e422 --- /dev/null +++ b/src/policyengine/data/qualification/uk_budget_critical_inputs.json @@ -0,0 +1,58 @@ +{ + "_comment": "Proposed Budget-critical input variables, pending review under cos d1344. Each name was checked on 11 October 2026 to be an input variable (Variable.is_input_variable()) in policyengine-uk 2.125.1 and a non-degenerate column of uk-data 1.58.0 enhanced_frs_2024_25.h5. A candidate fails the budget_inputs gate if any is missing or degenerate when it was usable in the previous certified pair; a gap present in both pairs needs review unless listed under accepted_gaps with an issue.", + "critical": [ + "accommodation_type", + "age", + "alcohol_and_tobacco_consumption", + "carers_allowance_reported", + "child_benefit_reported", + "child_tax_credit_reported", + "childcare_expenses", + "clothing_and_footwear_consumption", + "communication_consumption", + "corporate_wealth", + "council_tax", + "council_tax_band", + "diesel_spending", + "dividend_income", + "domestic_energy_consumption", + "education_consumption", + "employer_pension_contributions", + "food_and_non_alcoholic_beverages_consumption", + "gender", + "gross_financial_wealth", + "health_consumption", + "hours_worked", + "household_furnishings_consumption", + "household_owns_tv", + "household_weight", + "housing_benefit_reported", + "housing_water_and_electricity_consumption", + "is_disabled_for_benefits", + "main_residence_value", + "miscellaneous_consumption", + "net_financial_wealth", + "num_vehicles", + "other_residential_property_value", + "pension_credit_reported", + "personal_pension_contributions", + "petrol_spending", + "private_pension_income", + "property_income", + "property_purchased", + "recreation_consumption", + "region", + "rent", + "restaurants_and_hotels_consumption", + "savings", + "savings_interest_income", + "self_employment_income", + "tenure_type", + "transport_consumption", + "universal_credit_reported", + "working_tax_credit_reported", + "would_claim_child_benefit", + "would_claim_uc" + ], + "accepted_gaps": {} +} diff --git a/src/policyengine/data/qualification/uk_review_bounds.json b/src/policyengine/data/qualification/uk_review_bounds.json new file mode 100644 index 00000000..f19eb4a0 --- /dev/null +++ b/src/policyengine/data/qualification/uk_review_bounds.json @@ -0,0 +1,74 @@ +{ + "_comment": "Proposed per-kind review bounds for qualification metrics, pending cos d1344. A move needs review when |candidate - previous| exceeds max(relative * |previous|, absolute). Units follow the metric report: gbp (pounds), count (people or units), rate and share (fractions, so 0.005 is half a percentage point). They are review triggers, not acceptance criteria: a move inside the bounds is still in the evidence.", + "default": { + "relative": 0.02, + "absolute": 500000000.0 + }, + "kinds": { + "receipt": { + "relative": 0.02, + "absolute": 500000000.0, + "why": "2% or \u00a30.5bn: the Budget scorecard reports measures to \u00a30.1bn, and model fixes moving a head by more than 2% should be explained." + }, + "spending": { + "relative": 0.02, + "absolute": 500000000.0, + "why": "As receipts." + }, + "balance": { + "relative": 0.02, + "absolute": 500000000.0, + "why": "As receipts." + }, + "model_total": { + "relative": 0.02, + "absolute": 500000000.0, + "why": "As receipts." + }, + "household_total": { + "relative": 0.02, + "absolute": 500000000.0, + "why": "As receipts." + }, + "caseload": { + "relative": 0.03, + "absolute": 50000.0, + "why": "3% or 50,000 claimants: caseloads are calibrated targets; larger moves signal data or eligibility changes." + }, + "population": { + "relative": 0.01, + "absolute": 100000.0, + "why": "Population totals should barely move between pairs." + }, + "poverty": { + "relative": 0.0, + "absolute": 0.005, + "why": "Half a percentage point on a rate." + }, + "poverty_count": { + "relative": 0.03, + "absolute": 100000.0, + "why": "3% or 100,000 people." + }, + "inequality": { + "relative": 0.0, + "absolute": 0.005, + "why": "0.005 on a Gini-type index." + }, + "decile": { + "relative": 0.0, + "absolute": 0.005, + "why": "Half a point on a decile share." + }, + "double_count": { + "relative": 0.0, + "absolute": 1.0, + "why": "Any change in a counted-once check needs review." + }, + "reform": { + "relative": 0.05, + "absolute": 100000000.0, + "why": "5% or \u00a30.1bn on a reference reform costing." + } + } +} diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md new file mode 100644 index 00000000..23fd1b7c --- /dev/null +++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md @@ -0,0 +1,9 @@ +# Vendored policyengine-scorecard schemas + +Copied unchanged from PolicyEngine/policyengine-scorecard, branch +`w6/replay-variants`, commit `62704be` (`docs/uk_replay/schemas/`): the v1 +pre-promotion replay interface between policyengine.py qualification (W4) +and the replay corpus (W6). `policyengine.provenance.qualification` mirrors +them, and `tests/test_qualification_contracts.py` checks the mirrors and the +schemas accept and reject the same documents. Refresh by copying from a newer +scorecard commit and updating the commit above; never edit them by hand. diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json index 2aac386c..c5d8d9aa 100644 --- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json +++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json @@ -5,69 +5,178 @@ "description": "Returned by policyengine-scorecard for one qualification request. receipt_sha256 is the SHA-256 of the RFC 8785 (JCS) bytes of the receipt without that field. Flags describe movements against the base variant; they carry no verdict.", "type": "object", "additionalProperties": false, - "required": ["schema", "request_id", "status", "rejection", "variant_id", "variant_identity_sha256", "execution", "corpus", "integrity", "diff", "results", "receipt_sha256"], + "required": [ + "schema", + "request_id", + "status", + "rejection", + "variant_id", + "variant_identity_sha256", + "execution", + "corpus", + "integrity", + "diff", + "results", + "receipt_sha256" + ], "properties": { - "schema": {"const": "policyengine.uk-replay-receipt/v1"}, - "request_id": {"$ref": "#/$defs/sha256"}, - "status": {"enum": ["complete", "rejected", "failed"]}, + "schema": { + "const": "policyengine.uk-replay-receipt/v1" + }, + "request_id": { + "$ref": "#/$defs/sha256" + }, + "status": { + "enum": [ + "complete", + "rejected", + "failed" + ] + }, "rejection": { "oneOf": [ - {"type": "null"}, + { + "type": "null" + }, { "type": "object", "additionalProperties": false, - "required": ["code", "detail"], + "required": [ + "code", + "detail" + ], "properties": { - "code": {"enum": ["schema_invalid", "artifact_hash_mismatch", "release_bundle_mismatch", "incompatible_pair", "data_access_failed", "no_supported_years"]}, - "detail": {"type": "string", "minLength": 1} + "code": { + "enum": [ + "schema_invalid", + "artifact_hash_mismatch", + "release_bundle_mismatch", + "incompatible_pair", + "data_access_failed", + "no_supported_years" + ] + }, + "detail": { + "type": "string", + "minLength": 1 + } } } ] }, - "variant_id": {"type": ["string", "null"], "minLength": 1}, - "variant_identity_sha256": {"oneOf": [{"type": "null"}, {"$ref": "#/$defs/sha256"}]}, + "variant_id": { + "type": [ + "string", + "null" + ], + "minLength": 1 + }, + "variant_identity_sha256": { + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "#/$defs/sha256" + } + ] + }, "execution": { "oneOf": [ - {"type": "null"}, + { + "type": "null" + }, { "type": "object", "additionalProperties": false, - "required": ["packages", "packaged_bundle_manifest_sha256", "release_bundle", "dataset_sha256", "requirements_sha256", "python", "platform", "runner"], + "required": [ + "packages", + "packaged_bundle_manifest_sha256", + "release_bundle", + "dataset_sha256", + "requirements_sha256", + "python", + "platform", + "runner" + ], "properties": { "packages": { "type": "object", "additionalProperties": false, - "required": ["policyengine", "policyengine-uk", "policyengine-core"], + "required": [ + "policyengine", + "policyengine-uk", + "policyengine-core" + ], "properties": { - "policyengine": {"$ref": "#/$defs/installed_package"}, - "policyengine-uk": {"$ref": "#/$defs/installed_package"}, - "policyengine-core": {"$ref": "#/$defs/installed_package"} + "policyengine": { + "$ref": "#/$defs/installed_package" + }, + "policyengine-uk": { + "$ref": "#/$defs/installed_package" + }, + "policyengine-core": { + "$ref": "#/$defs/installed_package" + } + } + }, + "packaged_bundle_manifest_sha256": { + "$ref": "#/$defs/sha256" + }, + "release_bundle": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] } }, - "packaged_bundle_manifest_sha256": {"$ref": "#/$defs/sha256"}, - "release_bundle": {"type": "object", "additionalProperties": {"type": ["string", "null"]}}, - "dataset_sha256": {"$ref": "#/$defs/sha256"}, - "requirements_sha256": {"$ref": "#/$defs/sha256"}, - "python": {"type": "string", "pattern": "^3\\.[0-9]+\\.[0-9]+"}, - "platform": {"type": "string", "minLength": 1}, - "runner": {"type": "string", "minLength": 1} + "dataset_sha256": { + "$ref": "#/$defs/sha256" + }, + "requirements_sha256": { + "$ref": "#/$defs/sha256" + }, + "python": { + "type": "string", + "pattern": "^3\\.[0-9]+\\.[0-9]+" + }, + "platform": { + "type": "string", + "minLength": 1 + }, + "runner": { + "type": "string", + "minLength": 1 + } } } ] }, "corpus": { "oneOf": [ - {"type": "null"}, + { + "type": "null" + }, { "type": "object", "additionalProperties": false, - "required": ["corpus_version", "events"], + "required": [ + "corpus_version", + "events" + ], "properties": { - "corpus_version": {"type": "string", "minLength": 1}, + "corpus_version": { + "type": "string", + "minLength": 1 + }, "events": { "type": "object", "minProperties": 1, - "additionalProperties": {"$ref": "#/$defs/event_result"} + "additionalProperties": { + "$ref": "#/$defs/event_result" + } } } } @@ -76,24 +185,47 @@ "integrity": { "type": "object", "additionalProperties": false, - "required": ["status", "failures"], + "required": [ + "status", + "failures" + ], "properties": { "status": { "description": "complete: every supported measure-year ran and every receipt verified. incomplete: some supported pairs are missing. failed: a crash, a non-finite value, an identity mismatch after the run started, or a broken accounting identity.", - "enum": ["complete", "incomplete", "failed", "not_run"] + "enum": [ + "complete", + "incomplete", + "failed", + "not_run" + ] }, "failures": { "type": "array", "items": { "type": "object", "additionalProperties": false, - "required": ["code", "detail"], + "required": [ + "code", + "detail" + ], "properties": { - "code": {"type": "string", "minLength": 1}, - "detail": {"type": "string", "minLength": 1}, - "event": {"type": "string"}, - "measure_key": {"type": "string"}, - "year": {"type": "integer"} + "code": { + "type": "string", + "minLength": 1 + }, + "detail": { + "type": "string", + "minLength": 1 + }, + "event": { + "type": "string" + }, + "measure_key": { + "type": "string" + }, + "year": { + "type": "integer" + } } } } @@ -101,26 +233,67 @@ }, "diff": { "oneOf": [ - {"type": "null"}, + { + "type": "null" + }, { "type": "object", "additionalProperties": false, - "required": ["base_variant_id", "diff_sha256", "flag_counts", "flagged_rows"], + "required": [ + "base_variant_id", + "diff_sha256", + "flag_counts", + "flagged_rows" + ], "properties": { - "base_variant_id": {"type": "string", "minLength": 1}, - "diff_sha256": {"$ref": "#/$defs/sha256"}, + "base_variant_id": { + "type": "string", + "minLength": 1 + }, + "diff_sha256": { + "$ref": "#/$defs/sha256" + }, "flag_counts": { "type": "object", "additionalProperties": false, - "required": ["numerical", "structural", "coverage", "mapping", "support", "inertness", "construction"], + "required": [ + "numerical", + "structural", + "coverage", + "mapping", + "support", + "inertness", + "construction" + ], "properties": { - "numerical": {"type": "integer", "minimum": 0}, - "structural": {"type": "integer", "minimum": 0}, - "coverage": {"type": "integer", "minimum": 0}, - "mapping": {"type": "integer", "minimum": 0}, - "support": {"type": "integer", "minimum": 0}, - "inertness": {"type": "integer", "minimum": 0}, - "construction": {"type": "integer", "minimum": 0} + "numerical": { + "type": "integer", + "minimum": 0 + }, + "structural": { + "type": "integer", + "minimum": 0 + }, + "coverage": { + "type": "integer", + "minimum": 0 + }, + "mapping": { + "type": "integer", + "minimum": 0 + }, + "support": { + "type": "integer", + "minimum": 0 + }, + "inertness": { + "type": "integer", + "minimum": 0 + }, + "construction": { + "type": "integer", + "minimum": 0 + } } }, "flagged_rows": { @@ -128,21 +301,67 @@ "items": { "type": "object", "additionalProperties": false, - "required": ["event", "measure_key", "year", "level", "key", "flags", "base_gbp", "head_gbp"], + "required": [ + "event", + "measure_key", + "year", + "level", + "key", + "flags", + "base_gbp", + "head_gbp" + ], "properties": { - "event": {"type": "string", "minLength": 1}, - "measure_key": {"type": "string", "minLength": 1}, - "year": {"type": "integer"}, - "level": {"enum": ["source_row", "measure_year", "head"]}, - "key": {"type": "string", "minLength": 1}, + "event": { + "type": "string", + "minLength": 1 + }, + "measure_key": { + "type": "string", + "minLength": 1 + }, + "year": { + "type": "integer" + }, + "level": { + "enum": [ + "source_row", + "measure_year", + "head" + ] + }, + "key": { + "type": "string", + "minLength": 1 + }, "flags": { "type": "array", "minItems": 1, "uniqueItems": true, - "items": {"enum": ["numerical", "structural", "coverage", "mapping", "support", "inertness", "construction"]} + "items": { + "enum": [ + "numerical", + "structural", + "coverage", + "mapping", + "support", + "inertness", + "construction" + ] + } }, - "base_gbp": {"type": ["number", "null"]}, - "head_gbp": {"type": ["number", "null"]} + "base_gbp": { + "type": [ + "number", + "null" + ] + }, + "head_gbp": { + "type": [ + "number", + "null" + ] + } } } } @@ -153,74 +372,220 @@ "results": { "type": "object", "additionalProperties": false, - "required": ["repository", "ref", "path"], + "required": [ + "repository", + "ref", + "path" + ], "properties": { - "repository": {"const": "PolicyEngine/policyengine-scorecard"}, - "ref": {"type": "string", "minLength": 1}, - "commit": {"$ref": "#/$defs/sha1"}, - "path": {"type": "string", "minLength": 1} + "repository": { + "const": "PolicyEngine/policyengine-scorecard" + }, + "ref": { + "type": "string", + "minLength": 1 + }, + "commit": { + "$ref": "#/$defs/sha1" + }, + "path": { + "type": "string", + "minLength": 1 + }, + "manifest_sha256": { + "description": "SHA-256 of NAMESPACE_MANIFEST.json, which lists the SHA-256 of every file in the sealed result namespace except itself and the receipt.", + "$ref": "#/$defs/sha256" + } } }, - "receipt_sha256": {"$ref": "#/$defs/sha256"} + "receipt_sha256": { + "$ref": "#/$defs/sha256" + } }, "allOf": [ { - "if": {"properties": {"status": {"const": "rejected"}}}, - "then": {"properties": {"rejection": {"type": "object"}, "corpus": {"type": "null"}, "diff": {"type": "null"}}} + "if": { + "properties": { + "status": { + "const": "rejected" + } + } + }, + "then": { + "properties": { + "rejection": { + "type": "object" + }, + "corpus": { + "type": "null" + }, + "diff": { + "type": "null" + } + } + } }, { - "if": {"properties": {"status": {"enum": ["complete", "failed"]}}}, - "then": {"properties": {"rejection": {"type": "null"}, "variant_id": {"type": "string"}, "execution": {"type": "object"}}} + "if": { + "properties": { + "status": { + "enum": [ + "complete", + "failed" + ] + } + } + }, + "then": { + "properties": { + "rejection": { + "type": "null" + }, + "variant_id": { + "type": "string" + }, + "execution": { + "type": "object" + } + } + } }, { - "if": {"properties": {"status": {"const": "complete"}}}, - "then": {"properties": {"integrity": {"properties": {"status": {"enum": ["complete", "incomplete"]}}}, "corpus": {"type": "object"}}} + "if": { + "properties": { + "status": { + "const": "complete" + } + } + }, + "then": { + "properties": { + "integrity": { + "properties": { + "status": { + "enum": [ + "complete", + "incomplete" + ] + } + } + }, + "corpus": { + "type": "object" + } + } + } } ], "$defs": { - "sha256": {"type": "string", "pattern": "^[0-9a-f]{64}$"}, - "sha1": {"type": "string", "pattern": "^[0-9a-f]{40}$"}, + "sha256": { + "type": "string", + "pattern": "^[0-9a-f]{64}$" + }, + "sha1": { + "type": "string", + "pattern": "^[0-9a-f]{40}$" + }, "installed_package": { "type": "object", "additionalProperties": false, - "required": ["version", "record_sha256"], + "required": [ + "version", + "record_sha256" + ], "properties": { - "version": {"type": "string", "minLength": 1}, - "record_sha256": {"$ref": "#/$defs/sha256"}, - "wheel_sha256": {"$ref": "#/$defs/sha256"} + "version": { + "type": "string", + "minLength": 1 + }, + "record_sha256": { + "$ref": "#/$defs/sha256" + }, + "wheel_sha256": { + "$ref": "#/$defs/sha256" + } } }, "event_result": { "type": "object", "additionalProperties": false, - "required": ["registry_sha256", "supported_years", "unsupported_years", "run_manifest_sha256", "staging_manifest_sha256", "comparison_provenance_sha256", "artifacts", "full_supported_grid_complete", "inert_measure_years"], + "required": [ + "registry_sha256", + "supported_years", + "unsupported_years", + "run_manifest_sha256", + "staging_manifest_sha256", + "comparison_provenance_sha256", + "artifacts", + "full_supported_grid_complete", + "inert_measure_years" + ], "properties": { - "registry_sha256": {"$ref": "#/$defs/sha256"}, - "supported_years": {"type": "array", "items": {"type": "integer"}, "uniqueItems": true}, + "registry_sha256": { + "$ref": "#/$defs/sha256" + }, + "supported_years": { + "type": "array", + "items": { + "type": "integer" + }, + "uniqueItems": true + }, "unsupported_years": { "type": "array", "items": { "type": "object", "additionalProperties": false, - "required": ["year", "reason"], + "required": [ + "year", + "reason" + ], "properties": { - "year": {"type": "integer"}, - "reason": {"enum": ["before_data_year", "after_extension_end"]} + "year": { + "type": "integer" + }, + "reason": { + "enum": [ + "before_data_year", + "after_extension_end" + ] + } } } }, - "run_manifest_sha256": {"$ref": "#/$defs/sha256"}, - "staging_manifest_sha256": {"$ref": "#/$defs/sha256"}, - "comparison_provenance_sha256": {"$ref": "#/$defs/sha256"}, - "artifacts": {"type": "integer", "minimum": 0}, - "full_supported_grid_complete": {"type": "boolean"}, + "run_manifest_sha256": { + "$ref": "#/$defs/sha256" + }, + "staging_manifest_sha256": { + "$ref": "#/$defs/sha256" + }, + "comparison_provenance_sha256": { + "$ref": "#/$defs/sha256" + }, + "artifacts": { + "type": "integer", + "minimum": 0 + }, + "full_supported_grid_complete": { + "type": "boolean" + }, "inert_measure_years": { "type": "array", "items": { "type": "object", "additionalProperties": false, - "required": ["measure_key", "year"], - "properties": {"measure_key": {"type": "string"}, "year": {"type": "integer"}} + "required": [ + "measure_key", + "year" + ], + "properties": { + "measure_key": { + "type": "string" + }, + "year": { + "type": "integer" + } + } } } } diff --git a/src/policyengine/provenance/certification.py b/src/policyengine/provenance/certification.py index 3b4b27f1..f095cbe5 100644 --- a/src/policyengine/provenance/certification.py +++ b/src/policyengine/provenance/certification.py @@ -69,6 +69,14 @@ # fallback there exempts exactly this string from the fingerprint identity # check, so a claims-certified bundle stays importable without network access. BASIS_PUBLISHER_CLAIM = "legacy_compatible_model_package" +# The pair passed policyengine.py's automated candidate qualification. The +# claim is exact (``==`` model and core versions, one data release) and is +# valid only with a promotable qualification receipt for ``qualification_pair_id`` +# in the ledger; ``tests/test_certification_evidence.py`` refuses it otherwise. +BASIS_QUALIFIED_PAIR = "qualified_exact_pair" +QUALIFICATION_LEDGER_URL = ( + "https://github.com/PolicyEngine/policyengine.py/tree/uk-qualification-ledger" +) POPULACE_US_SOURCE_COVERAGE_FILE = "us_source_coverage.json" # The Populace US producer publishes under `microcosm-data` since the # source-enrichment releases; `populace-data` is its earlier name. Both denote @@ -226,15 +234,24 @@ def validate_release_manifest( manifest: DataReleaseManifest, model_package: str, model_version: str, + *, + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> tuple[str, list[str]]: """Hard checks raise; returns ``(compatibility_basis, warnings)``. The certification gate (docs/release-bundles.md): a data release may be certified for a model version only when the model exactly matches - the build-time model, or the publisher's ``compatible_model_packages`` - covers it. The publisher-claim basis is recorded and warned about — - it is the data publisher's assertion, made good only by this repo's - test suite passing on the pinned pair. + the build-time model, the publisher's ``compatible_model_packages`` + covers it, or (``qualified_pair_id``) policyengine.py's automated + qualification tested exactly this model, core and data release. The + publisher-claim basis is recorded and warned about — it is the data + publisher's assertion, made good only by this repo's test suite passing + on the pinned pair. A qualified pair is never widened into a range. + + When ``core_version`` is given, the core must also be the build-time + core, be covered by ``compatible_core_packages``, or be part of the + qualified pair. """ warnings: list[str] = [] if "national" not in manifest.default_datasets: @@ -267,6 +284,9 @@ def validate_release_manifest( _specifier_matches(model_version, specifier) for specifier in claim_specifiers ) + if core_version is not None: + _check_core_compatibility(manifest, core_version, qualified_pair_id, warnings) + if built_with == model_version: return BASIS_BUILT_WITH, warnings if claim_matches: @@ -277,11 +297,61 @@ def validate_release_manifest( "suite is the arbiter" ) return BASIS_PUBLISHER_CLAIM, warnings + if qualified_pair_id is not None: + if core_version is None: + raise CertificationError( + "A qualified exact pair names its core version; pass core_version." + ) + warnings.append( + f"certifying exactly {model_package}=={model_version} with " + f"policyengine-core=={core_version} on automated qualification of " + f"pair {qualified_pair_id}; the certificate stands only with a " + "promotable qualification receipt for that pair in the ledger" + ) + return BASIS_QUALIFIED_PAIR, warnings raise CertificationError( f"{model_package} {model_version} matches neither the build-time " f"model ({built_with or 'unrecorded'}) nor any publisher " f"compatibility claim {claim_specifiers or '(none declared)'}; " - "a new data build or a published compatibility claim is required." + "a new data build, a published compatibility claim or an automated " + "qualification of the exact pair is required." + ) + + +def _check_core_compatibility( + manifest: DataReleaseManifest, + core_version: str, + qualified_pair_id: Optional[str], + warnings: list[str], +) -> None: + """The core must be the build core, publisher-claimed, or qualified.""" + + build = manifest.build + built_with_core = ( + build.built_with_core_package.version + if build is not None and build.built_with_core_package is not None + else None + ) + core_claims = [ + package.specifier + for package in manifest.compatible_core_packages + if package.name == "policyengine-core" + ] + if built_with_core == core_version or any( + _specifier_matches(core_version, specifier) for specifier in core_claims + ): + return + if qualified_pair_id is not None: + warnings.append( + f"policyengine-core {core_version} is outside the publisher's core " + f"claims {core_claims or '(none declared)'}; covered by qualification " + f"of pair {qualified_pair_id}" + ) + return + raise CertificationError( + f"policyengine-core {core_version} matches neither the build-time core " + f"({built_with_core or 'unrecorded'}) nor any publisher core claim " + f"{core_claims or '(none declared)'}." ) @@ -591,6 +661,8 @@ def build_country_manifest_payload( model_version: str, model_wheel: dict, compatibility_basis: str = BASIS_BUILT_WITH, + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> dict: """Map the data release manifest to the vendored country manifest.""" default_dataset = manifest.default_datasets["national"] @@ -651,6 +723,13 @@ def build_country_manifest_payload( "certified_for_model_version": model_version, "certified_by": CERTIFIED_BY, } + if core_version is not None: + certification["certified_for_core_version"] = core_version + if qualified_pair_id is not None: + certification["qualification_pair_id"] = qualified_pair_id + certification["qualification_ledger_url"] = ( + f"{QUALIFICATION_LEDGER_URL}/{country}/{qualified_pair_id}" + ) certified_artifact: dict = { "data_package": { "name": manifest.data_package.name, @@ -747,6 +826,8 @@ def certify( regional_manifest_uri: Optional[str] = None, regional_artifact_prefix: str = "states/", regional_path_template: str = "states/{state_code}.h5", + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> tuple[dict, str, list[str]]: raise NotImplementedError @@ -766,6 +847,8 @@ def certify( regional_manifest_uri: Optional[str] = None, regional_artifact_prefix: str = "states/", regional_path_template: str = "states/{state_code}.h5", + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> tuple[dict, str, list[str]]: raise CertificationError( "Legacy data-producer certification updates are not implemented in " @@ -788,6 +871,8 @@ def certify( regional_manifest_uri: Optional[str] = None, regional_artifact_prefix: str = "states/", regional_path_template: str = "states/{state_code}.h5", + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> tuple[dict, str, list[str]]: manifest, manifest_sha256, uri_parts = fetch_release_manifest( manifest_uri, token=token @@ -810,7 +895,11 @@ def certify( path_template=regional_path_template, ) compatibility_basis, warnings = validate_release_manifest( - manifest, model_package, model_version + manifest, + model_package, + model_version, + core_version=core_version, + qualified_pair_id=qualified_pair_id, ) for filename in required_supplemental_release_files( @@ -838,6 +927,12 @@ def certify( model_version=model_version, model_wheel=model_wheel or {}, compatibility_basis=compatibility_basis, + core_version=core_version, + qualified_pair_id=( + qualified_pair_id + if compatibility_basis == BASIS_QUALIFIED_PAIR + else None + ), ) if check_artifacts and should_validate_vendored_artifacts( country, manifest, uri_parts @@ -898,7 +993,17 @@ def certify_data_release( regional_manifest_uri: Optional[str] = None, regional_artifact_prefix: str = "states/", regional_path_template: str = "states/{state_code}.h5", + core_version: Optional[str] = None, + qualified_pair_id: Optional[str] = None, ) -> CertificationResult: + """Certify a data release into the bundle manifest. + + ``core_version`` adds the core compatibility check and pins the core in + the bundle's ``packages``. ``qualified_pair_id`` admits the exact model, + core and data release when neither the build-time model nor a publisher + claim covers them; the certificate then names the pair, whose promotable + qualification receipt must be in the ledger. + """ if country not in COUNTRY_MODEL_PACKAGES: raise CertificationError(f"Unknown country {country!r}.") model_package = COUNTRY_MODEL_PACKAGES[country] @@ -915,6 +1020,8 @@ def certify_data_release( regional_manifest_uri=regional_manifest_uri, regional_artifact_prefix=regional_artifact_prefix, regional_path_template=regional_path_template, + core_version=core_version, + qualified_pair_id=qualified_pair_id, ) bundle_path = bundle_path or default_bundle_source_path() bundle = json.loads(bundle_path.read_text()) @@ -924,6 +1031,8 @@ def certify_data_release( ) if model_package in bundle.get("packages", {}): bundle["packages"][model_package]["version"] = model_version + if core_version is not None and "policyengine-core" in bundle.get("packages", {}): + bundle["packages"]["policyengine-core"]["version"] = core_version bundle_path.write_text(json.dumps(bundle, indent=2, sort_keys=True) + "\n") return CertificationResult( diff --git a/src/policyengine/provenance/manifest.py b/src/policyengine/provenance/manifest.py index 0995c0d5..82647384 100644 --- a/src/policyengine/provenance/manifest.py +++ b/src/policyengine/provenance/manifest.py @@ -155,6 +155,16 @@ class DataCertification(BaseModel): built_with_model_git_sha: Optional[str] = None data_build_fingerprint: Optional[str] = None certified_by: Optional[str] = None + certified_for_core_version: Optional[str] = None + qualification_pair_id: Optional[str] = None + qualification_ledger_url: Optional[str] = None + + +#: Bases whose runtime model legitimately differs from the data's build-time +#: model, so the build fingerprint is not expected to match. +CLAIM_BASED_COMPATIBILITY = frozenset( + {"legacy_compatible_model_package", "qualified_exact_pair"} +) class CertifiedDataArtifact(BaseModel): @@ -407,7 +417,7 @@ def certify_data_release_compatibility( runtime_data_build_fingerprint is not None and bundled_certification.data_build_fingerprint is not None and bundled_certification.compatibility_basis - != "legacy_compatible_model_package" + not in CLAIM_BASED_COMPATIBILITY and runtime_data_build_fingerprint != bundled_certification.data_build_fingerprint ): @@ -514,6 +524,24 @@ def certify_data_release_compatibility( ), ) + # An automated qualification of exactly this model and data build: the + # bundled certificate names the pair, and the ledger evidence for it is + # enforced when the bundle is built (tests/test_certification_evidence.py). + bundled_certification = country_manifest.certification + remote_build_id = ( + data_release_manifest.build.build_id + if data_release_manifest.build is not None + else None + ) + if ( + bundled_certification is not None + and bundled_certification.compatibility_basis == "qualified_exact_pair" + and bundled_certification.certified_for_model_version == runtime_model_version + and bundled_certification.qualification_pair_id is not None + and bundled_certification.data_build_id == remote_build_id + ): + return bundled_certification + raise ValueError( "Data release manifest is not certified for the runtime model version " f"{runtime_model_version} in country '{country_id}'." diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py index bcfeb016..fa300731 100644 --- a/src/policyengine/provenance/qualification.py +++ b/src/policyengine/provenance/qualification.py @@ -623,6 +623,11 @@ class ResultsLocation(_Mirror): ref: str = Field(min_length=1) commit: Optional[str] = Field(default=None, pattern=_SHA1) path: str = Field(min_length=1) + manifest_sha256: Optional[str] = Field( + default=None, + pattern=SHA256_PATTERN, + description="Digest of NAMESPACE_MANIFEST.json for the sealed result namespace.", + ) class ReplayReceipt(_Mirror): diff --git a/src/policyengine/provenance/qualification_ledger.py b/src/policyengine/provenance/qualification_ledger.py new file mode 100644 index 00000000..ab1835bb --- /dev/null +++ b/src/policyengine/provenance/qualification_ledger.py @@ -0,0 +1,189 @@ +"""The qualification ledger: durable evidence for every candidate attempt. + +The ledger is the orphan branch ``uk-qualification-ledger`` of +PolicyEngine/policyengine.py. Each candidate pair owns one directory, so +concurrent qualifications never write the same file:: + + // + pair.json the CandidatePair + qualification_receipt.json the latest terminal receipt for the pair + attempts// + harness.json the candidate commit that ran it + gates/.json each gate's evidence + replay/request.json the request sent to the scorecard + replay/status.json the terminal status read back + replay/receipt.json the receipt bytes read back + qualification_receipt.json this attempt's receipt + +Failed and incomplete attempts are kept: the ledger never deletes evidence. +A bundle certificate with basis ``qualified_exact_pair`` must point at a pair +whose latest receipt is promotable and matches the certificate exactly +(:func:`verify_certification_evidence`). +""" + +from __future__ import annotations + +import json +from collections.abc import Callable, Iterable, Mapping +from pathlib import Path +from typing import Any, Optional + +from policyengine.provenance.qualification import QualificationReceipt + +LEDGER_REPOSITORY = "PolicyEngine/policyengine.py" +LEDGER_BRANCH = "uk-qualification-ledger" +RAW_LEDGER_URL = ( + f"https://raw.githubusercontent.com/{LEDGER_REPOSITORY}/{LEDGER_BRANCH}" +) + +__all__ = [ + "LEDGER_BRANCH", + "LEDGER_REPOSITORY", + "attempt_directory", + "fetch_ledger_receipt", + "latest_receipts", + "pair_directory", + "pending_attempts", + "verify_certification_evidence", + "write_json", +] + + +def write_json(path: Path, value: Any) -> None: + """Write readable, deterministic JSON (digests are over the JSON value).""" + + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text( + json.dumps(value, indent=2, sort_keys=True, ensure_ascii=False) + "\n", + encoding="utf-8", + ) + + +def read_json(path: Path) -> Any: + return json.loads(path.read_text(encoding="utf-8")) + + +def pair_directory(root: Path, country_id: str, pair_id: str) -> Path: + return root / country_id / pair_id + + +def attempt_directory( + root: Path, country_id: str, pair_id: str, attempt_key: str +) -> Path: + if "/" in attempt_key or attempt_key in ("", ".", ".."): + raise ValueError(f"Invalid attempt key {attempt_key!r}.") + return pair_directory(root, country_id, pair_id) / "attempts" / attempt_key + + +def latest_receipts(root: Path, country_id: str = "uk") -> list[QualificationReceipt]: + """Every pair's latest terminal receipt in a checked-out ledger.""" + + base = root / country_id + if not base.is_dir(): + return [] + receipts = [] + for path in sorted(base.glob("*/qualification_receipt.json")): + receipts.append(QualificationReceipt.model_validate(read_json(path))) + return receipts + + +def pending_attempts(root: Path, country_id: str = "uk") -> list[Path]: + """Attempts that sent a replay request and have no receipt yet.""" + + base = root / country_id + if not base.is_dir(): + return [] + return sorted( + path.parent.parent + for path in base.glob("*/attempts/*/replay/request.json") + if not (path.parent.parent / "qualification_receipt.json").exists() + ) + + +def fetch_ledger_receipt( + country_id: str, + pair_id: str, + *, + get: Optional[Callable[..., Any]] = None, +) -> Optional[QualificationReceipt]: + """Read a pair's latest receipt from the published ledger branch.""" + + if get is None: + import requests + + get = requests.get + response = get( + f"{RAW_LEDGER_URL}/{country_id}/{pair_id}/qualification_receipt.json", + timeout=30, + ) + if response.status_code == 404: + return None + response.raise_for_status() + return QualificationReceipt.model_validate_json(response.text) + + +def verify_certification_evidence( + record: Mapping[str, Any], + receipt: Optional[QualificationReceipt], +) -> list[str]: + """Problems with a bundle certification record's qualification evidence. + + Records on any basis other than ``qualified_exact_pair`` need no ledger + evidence and return no problems. A qualified exact pair needs a + promotable receipt for exactly the model wheel, core, data release and + dataset bytes the record certifies. + """ + + certification = record.get("certification") or {} + if certification.get("compatibility_basis") != "qualified_exact_pair": + return [] + pair_id = certification.get("qualification_pair_id") + if not pair_id: + return ["qualified_exact_pair certificate names no qualification_pair_id"] + if receipt is None: + return [f"no qualification receipt in the ledger for pair {pair_id}"] + + problems: list[str] = [] + if receipt.pair_id != pair_id: + problems.append("ledger receipt is for a different pair") + if not receipt.promotable: + problems.append( + f"ledger receipt verdict is {receipt.verdict} without an accepted review" + ) + pair = receipt.pair + model = record.get("model_package") or {} + data = record.get("data_package") or {} + artifact = record.get("certified_data_artifact") or {} + expected: Iterable[tuple[str, Any, Any]] = ( + ( + "model version", + pair.model.version, + certification.get("certified_for_model_version"), + ), + ("model version in bundle", pair.model.version, model.get("version")), + ( + "model wheel sha256", + pair.model.wheel_sha256, + model.get("sha256", pair.model.wheel_sha256), + ), + ( + "core version", + pair.core.version, + certification.get("certified_for_core_version"), + ), + ("data release", pair.data.release_version, data.get("version")), + ( + "release manifest revision", + pair.data.release_manifest_revision, + data.get("release_manifest_revision"), + ), + ("default dataset", pair.data.dataset, record.get("default_dataset")), + ("dataset sha256", pair.data.dataset_sha256, artifact.get("sha256")), + ("data build id", pair.data.build_id, certification.get("data_build_id")), + ) + for label, qualified, certified in expected: + if qualified != certified: + problems.append( + f"{label}: qualified {qualified!r}, certified {certified!r}" + ) + return problems diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py new file mode 100644 index 00000000..aa8f40c5 --- /dev/null +++ b/src/policyengine/provenance/uk_candidate.py @@ -0,0 +1,1560 @@ +"""Mandatory local qualification gates for a UK model/data candidate. + +Each gate returns a :class:`~policyengine.provenance.qualification.GateResult` +and an evidence dict whose ``content_sha256`` the result records. No gate has +a skip path: a gate whose harness is missing reports ``unavailable`` (the +candidate is incomplete), a gate that crashes reports ``error`` (rejected), +and a failed check reports ``fail`` (rejected). The replay gate is evaluated +separately (:func:`policyengine.provenance.qualification.evaluate_replay_receipt`). + +I/O is injected (metadata readers, HTTP getters, importers, year projectors) +so every gate is testable offline. :func:`run_candidate_gates` wires the real +implementations for the qualification workflow. +""" + +from __future__ import annotations + +import base64 +import csv +import hashlib +import importlib +import io +import json +import math +import traceback +import zipfile +from collections.abc import Callable, Iterable, Mapping, Sequence +from importlib import metadata as importlib_metadata +from pathlib import Path +from typing import Any, Optional + +from packaging.requirements import Requirement +from packaging.specifiers import SpecifierSet +from packaging.version import Version + +from policyengine.provenance.manifest import DataReleaseManifest, _specifier_matches +from policyengine.provenance.qualification import ( + CandidatePair, + GateResult, + QualificationHarness, +) +from policyengine.provenance.receipt import content_sha256 +from policyengine.utils.hashing import sha256_file + +Evidence = dict[str, Any] +GateOutcome = tuple[GateResult, Evidence] + +#: Files an installer adds to a distribution that are not in the wheel RECORD. +INSTALLER_FILES = frozenset( + {"INSTALLER", "REQUESTED", "direct_url.json", "uv_cache.json"} +) +UK_SINGLE_YEAR_KEYS = ("time_period", "person", "benunit", "household") +ENTITY_TABLES = ("person", "benunit", "household") + + +def _json_safe(value: Any) -> Any: + """Evidence as strict JSON: non-finite numbers become their names.""" + + if isinstance(value, float) and not math.isfinite(value): + return ( + "NaN" if math.isnan(value) else ("Infinity" if value > 0 else "-Infinity") + ) + if isinstance(value, Mapping): + return {str(key): _json_safe(item) for key, item in value.items()} + if isinstance(value, (list, tuple)): + return [_json_safe(item) for item in value] + return value + + +def evidence_sha256(evidence: Any) -> str: + """Digest of evidence that may contain non-finite numbers.""" + + return content_sha256(_json_safe(evidence)) + + +def _result( + gate_id: str, + status: str, + summary: str, + evidence: Evidence, + details: Optional[Mapping[str, Any]] = None, +) -> GateOutcome: + result = GateResult( + gate_id=gate_id, + status=status, # type: ignore[arg-type] + summary=summary, + evidence_sha256=evidence_sha256(evidence), + details=_json_safe(dict(details or {})), + ) + return result, _json_safe(evidence) + + +# --- 1. Installed versions --------------------------------------------------- + + +def installed_versions( + pair: CandidatePair, + harness: QualificationHarness, + *, + metadata: Any = importlib_metadata, +) -> GateOutcome: + """Installed wrapper, model and core equal the candidate; requirements hold.""" + + expected = { + "policyengine": harness.policyengine_version, + pair.model.name: pair.model.version, + pair.core.name: pair.core.version, + } + installed: dict[str, Optional[str]] = {} + problems: list[str] = [] + for name, version in expected.items(): + try: + installed[name] = metadata.version(name) + except metadata.PackageNotFoundError: + installed[name] = None + problems.append(f"{name} is not installed") + continue + if installed[name] != version: + problems.append(f"{name} {installed[name]} is installed, not {version}") + + unmet: list[str] = [] + for name in expected: + if installed.get(name) is None: + continue + for line in metadata.requires(name) or []: + requirement = Requirement(line) + if requirement.marker is not None and not requirement.marker.evaluate( + {"extra": ""} + ): + continue + try: + found = metadata.version(requirement.name) + except metadata.PackageNotFoundError: + unmet.append(f"{name} needs {requirement}, which is not installed") + continue + if requirement.specifier and not requirement.specifier.contains( + found, prereleases=True + ): + unmet.append(f"{name} needs {requirement}; {found} is installed") + problems.extend(unmet) + evidence = { + "expected": expected, + "installed": installed, + "unmet_requirements": unmet, + } + if problems: + return _result("installed_versions", "fail", "; ".join(problems), evidence) + return _result( + "installed_versions", + "pass", + f"policyengine {harness.policyengine_version}, {pair.model.name} {pair.model.version} and {pair.core.name} {pair.core.version} are installed and " + "their requirements hold.", + evidence, + ) + + +# --- 2. Wheel hashes ----------------------------------------------------------- + + +def record_digest_to_hex(value: str) -> str: + """Convert a RECORD ``sha256=`` digest to hex.""" + + algorithm, _, encoded = value.partition("=") + if algorithm != "sha256": + raise ValueError(f"Unsupported RECORD hash {algorithm!r}.") + padded = encoded + "=" * (-len(encoded) % 4) + return base64.urlsafe_b64decode(padded).hex() + + +def parse_record(text: str) -> dict[str, Optional[str]]: + """``{path: hex sha256 or None}`` from a RECORD file.""" + + entries: dict[str, Optional[str]] = {} + for row in csv.reader(io.StringIO(text)): + if not row: + continue + path, digest = row[0], (row[1] if len(row) > 1 else "") + entries[path] = record_digest_to_hex(digest) if digest else None + return entries + + +def wheel_record(wheel_path: Path) -> dict[str, Optional[str]]: + with zipfile.ZipFile(wheel_path) as archive: + names = [ + name for name in archive.namelist() if name.endswith(".dist-info/RECORD") + ] + if len(names) != 1: + raise ValueError(f"{wheel_path.name} has {len(names)} RECORD files.") + return parse_record(archive.read(names[0]).decode("utf-8")) + + +def verify_installed_against_wheel( + name: str, wheel_path: Path, *, metadata: Any = importlib_metadata +) -> Evidence: + """Check every hashed wheel file is installed with the same bytes. + + Returns evidence; raises nothing. ``problems`` lists every mismatch. + """ + + expected = wheel_record(wheel_path) + distribution = metadata.distribution(name) + installed: dict[str, Optional[str]] = {} + for file in distribution.files or []: + installed[str(file)] = ( + record_digest_to_hex(f"{file.hash.mode}={file.hash.value}") + if file.hash is not None + else None + ) + problems: list[str] = [] + verified = 0 + for path, digest in sorted(expected.items()): + if digest is None: + continue + if installed.get(path, "absent") != digest: + problems.append(f"{path}: installed RECORD differs from the wheel") + continue + located = Path(distribution.locate_file(path)) + if not located.is_file(): + problems.append(f"{path}: missing on disk") + continue + if sha256_file(located) != digest: + problems.append(f"{path}: bytes differ from the wheel") + continue + verified += 1 + extra = sorted( + path + for path in installed + if path not in expected + and not path.endswith(".pyc") + and Path(path).name not in INSTALLER_FILES + and not path.endswith(".dist-info/RECORD") + ) + problems.extend(f"{path}: installed but not in the wheel" for path in extra) + return { + "wheel": wheel_path.name, + "wheel_sha256": sha256_file(wheel_path), + "files_verified": verified, + "unexpected_installed_files": extra, + "problems": problems, + } + + +def wheel_hashes( + pair: CandidatePair, + *, + wheel_paths: Mapping[str, Path], + pypi_digests: Mapping[str, str], + metadata: Any = importlib_metadata, +) -> GateOutcome: + """Downloaded wheels match PyPI and the pin; installed files match the wheels.""" + + evidence: Evidence = {} + problems: list[str] = [] + for package in (pair.model, pair.core): + path = wheel_paths.get(package.name) + if path is None or not Path(path).is_file(): + problems.append(f"no downloaded wheel for {package.name}") + continue + actual = sha256_file(path) + if actual != package.wheel_sha256: + problems.append( + f"{package.name} wheel is {actual}, pinned {package.wheel_sha256}" + ) + if pypi_digests.get(package.name) != package.wheel_sha256: + problems.append(f"PyPI publishes a different {package.name} wheel digest") + verification = verify_installed_against_wheel( + package.name, Path(path), metadata=metadata + ) + evidence[package.name] = verification + problems.extend(f"{package.name} {item}" for item in verification["problems"]) + if problems: + return _result("wheel_hashes", "fail", "; ".join(problems[:10]), evidence) + counts = ", ".join( + f"{name} {item['files_verified']} files" for name, item in evidence.items() + ) + return _result( + "wheel_hashes", + "pass", + f"Installed files match the pinned PyPI wheels ({counts}).", + evidence, + ) + + +def verified_package_hashes(pair: CandidatePair) -> dict[str, tuple[str, str]]: + """``package_hashes`` for ``build_execution_receipt`` after ``wheel_hashes`` passes.""" + + return { + pair.model.name: (pair.model.wheel_sha256, "installed_record_verified"), + pair.core.name: (pair.core.wheel_sha256, "installed_record_verified"), + } + + +# --- 3. Core compatibility ----------------------------------------------------- + + +def core_compatibility( + pair: CandidatePair, + release_manifest: DataReleaseManifest, + *, + model_requires_core: str, +) -> GateOutcome: + """The core satisfies the model; publisher claims are recorded, not required.""" + + problems: list[str] = [] + if not SpecifierSet(model_requires_core).contains( + pair.core.version, prereleases=True + ): + problems.append( + f"{pair.model.name} {pair.model.version} requires policyengine-core" + f"{model_requires_core}; the candidate core is {pair.core.version}" + ) + build = release_manifest.build + built_with = build.built_with_model_package if build is not None else None + if built_with is not None and built_with.name != pair.model.name: + problems.append( + f"the data was built with {built_with.name}, not {pair.model.name}" + ) + model_claims = [ + package.specifier + for package in release_manifest.compatible_model_packages + if package.name == pair.model.name + ] + core_claims = [ + package.specifier + for package in release_manifest.compatible_core_packages + if package.name == pair.core.name + ] + evidence = { + "model_requires_core": model_requires_core, + "built_with_model_version": built_with.version if built_with else None, + "built_with_core_version": ( + build.built_with_core_package.version + if build is not None and build.built_with_core_package is not None + else None + ), + "publisher_model_claims": model_claims, + "publisher_core_claims": core_claims, + "publisher_claim_covers_model": any( + _specifier_matches(pair.model.version, item) for item in model_claims + ), + "publisher_claim_covers_core": any( + _specifier_matches(pair.core.version, item) for item in core_claims + ), + } + if problems: + return _result("core_compatibility", "fail", "; ".join(problems), evidence) + coverage = ( + "the publisher's claims cover both" + if evidence["publisher_claim_covers_model"] + and evidence["publisher_claim_covers_core"] + else "certification will record an exact qualified pair, since the publisher's claims do not cover both" + ) + return _result( + "core_compatibility", + "pass", + f"policyengine-core {pair.core.version} satisfies {pair.model.name}{model_requires_core}; {coverage}.", + evidence, + details={ + "publisher_claim_covers_model": evidence["publisher_claim_covers_model"], + "publisher_claim_covers_core": evidence["publisher_claim_covers_core"], + }, + ) + + +# --- 4. Data access ------------------------------------------------------------ + + +def _hf_url(repo_id: str, repo_type: str, revision: str, path: str) -> str: + prefix = "datasets/" if repo_type == "dataset" else "" + return f"https://huggingface.co/{prefix}{repo_id}/resolve/{revision}/{path}" + + +def data_access( + pair: CandidatePair, + *, + get: Callable[..., Any], + head: Callable[..., Any], + token: Optional[str], +) -> tuple[GateResult, Evidence, Optional[DataReleaseManifest]]: + """Authenticated access to the exact manifest and every artifact.""" + + data = pair.data + evidence: Evidence = {"artifacts": {}} + if not token: + result, evidence = _result( + "data_access", + "fail", + "No Hugging Face token is configured; the UK data is private.", + evidence, + ) + return result, evidence, None + headers = {"Authorization": f"Bearer {token}"} + manifest_url = _hf_url( + data.repo_id, + data.repo_type, + data.release_manifest_revision, + data.release_manifest_path, + ) + response = get(manifest_url, headers=headers, timeout=60) + evidence["manifest_status"] = response.status_code + if response.status_code != 200: + result, evidence = _result( + "data_access", + "fail", + f"The release manifest returned HTTP {response.status_code}.", + evidence, + ) + return result, evidence, None + manifest_sha256 = hashlib.sha256(response.content).hexdigest() + evidence["manifest_sha256"] = manifest_sha256 + problems = [] + if manifest_sha256 != data.release_manifest_sha256: + problems.append("the release manifest bytes differ from the candidate's") + manifest = DataReleaseManifest.model_validate_json(response.content) + for name, artifact in sorted(manifest.artifacts.items()): + url = _hf_url( + artifact.repo_id, + artifact.repo_type or data.repo_type, + artifact.revision, + artifact.path, + ) + status = head( + url, headers=headers, timeout=60, allow_redirects=True + ).status_code + evidence["artifacts"][name] = status + if status != 200: + problems.append(f"{name} returned HTTP {status}") + dataset_url = _hf_url( + data.repo_id, data.repo_type, data.dataset_revision, data.dataset_path + ) + anonymous = head(dataset_url, timeout=60, allow_redirects=True).status_code + evidence["anonymous_dataset_status"] = anonymous + if anonymous == 200: + problems.append( + "the dataset is readable without credentials, so the authenticated path was not tested" + ) + if problems: + result, evidence = _result("data_access", "fail", "; ".join(problems), evidence) + return result, evidence, manifest + result, evidence = _result( + "data_access", + "pass", + f"Read the release manifest and {len(manifest.artifacts)} artifacts with the " + f"configured credential; anonymous access returned HTTP {anonymous}.", + evidence, + ) + return result, evidence, manifest + + +# --- 5. Dataset bytes ---------------------------------------------------------- + + +def h5_keys(path: Path) -> list[str]: + import h5py + + with h5py.File(path, "r") as stream: + return sorted(stream.keys()) + + +def dataset_bytes(pair: CandidatePair, dataset_path: Path) -> GateOutcome: + """The simulated file is the candidate's bytes and has the UK layout.""" + + data = pair.data + actual = sha256_file(dataset_path) + size = dataset_path.stat().st_size + keys = h5_keys(dataset_path) + evidence = {"sha256": actual, "size_bytes": size, "h5_keys": keys} + problems = [] + if actual != data.dataset_sha256: + problems.append(f"sha256 {actual}, expected {data.dataset_sha256}") + if size != data.size_bytes: + problems.append(f"{size} bytes, expected {data.size_bytes}") + missing_keys = [key for key in UK_SINGLE_YEAR_KEYS if key not in keys] + if missing_keys: + problems.append(f"missing H5 keys {missing_keys}") + if problems: + return _result("dataset_bytes", "fail", "; ".join(problems), evidence) + return _result( + "dataset_bytes", + "pass", + f"{data.dataset} is the pinned {size:,} bytes with the UK single-year layout.", + evidence, + ) + + +# --- 6. Supported years -------------------------------------------------------- + + +def data_year(dataset_path: Path) -> int: + import pandas as pd + + with pd.HDFStore(dataset_path, mode="r") as store: + return int(str(store["time_period"].iloc[0])[:4]) + + +def projected_years_from_model(dataset_path: Path) -> list[int]: + """The years policyengine-uk projects a single-year dataset to. + + Builds the multi-year dataset exactly as ``policyengine_uk.Simulation`` + does for a single-year file (``extend_single_year_dataset`` with the + system's parameters), without running any formula. + """ + + from policyengine_uk.data.dataset_schema import UKSingleYearDataset + from policyengine_uk.data.economic_assumptions import extend_single_year_dataset + from policyengine_uk.system import system + + multi_year = extend_single_year_dataset( + UKSingleYearDataset(str(dataset_path)), system.parameters + ) + years = getattr(multi_year, "years", None) + if years is None: + years = list(multi_year.datasets) + return sorted(int(year) for year in years) + + +def supported_years( + pair: CandidatePair, + dataset_path: Path, + *, + required_years: Sequence[int], + budget_horizon_years: Sequence[int], + previous_supported_years: Optional[Sequence[int]], + projected_years: Callable[[Path], list[int]] = projected_years_from_model, +) -> GateOutcome: + """Required years are inside the data's projection; support never shrinks. + + Support comes from the data and the model's projection, never from a + calculation succeeding: policyengine-core fills years outside the + projection (carrying or uprating the latest inputs), so a result there + is not evidence of support. + """ + + first = data_year(dataset_path) + years = projected_years(dataset_path) + supported = sorted(year for year in years if year >= first) + missing_required = sorted(set(required_years) - set(supported)) + lost = sorted(set(previous_supported_years or []) - set(supported)) + outside_horizon = sorted(set(budget_horizon_years) - set(supported)) + evidence = { + "data_year": first, + "supported_years": supported, + "required_years": sorted(required_years), + "budget_horizon_years": sorted(budget_horizon_years), + "previous_supported_years": sorted(previous_supported_years or []), + "lost_years": lost, + "outside_projection": outside_horizon, + } + details = {"supported_years": supported, "outside_projection": outside_horizon} + if not supported: + return _result( + "supported_years", + "fail", + f"The dataset supports no year: its data year is {first} and the model " + f"projects only to {max(years) if years else 'nothing'}.", + evidence, + details, + ) + if missing_required or lost: + parts = [] + if missing_required: + parts.append( + f"required years {missing_required} are outside the projection" + ) + if lost: + parts.append(f"years {lost} were supported by the previous certificate") + return _result("supported_years", "fail", "; ".join(parts), evidence, details) + if outside_horizon: + return _result( + "supported_years", + "needs_review", + f"Budget horizon years {outside_horizon} are outside the dataset's projection " + f"({supported[0]}–{supported[-1]}); results there are provisional.", + evidence, + details, + ) + return _result( + "supported_years", + "pass", + f"Supports {supported[0]}–{supported[-1]}, covering the required and horizon years.", + evidence, + details, + ) + + +# --- 7. Budget inputs ---------------------------------------------------------- + + +def dataset_columns(dataset_path: Path) -> dict[str, Any]: + """``{entity: DataFrame}`` for the UK entity tables.""" + + import pandas as pd + + with pd.HDFStore(dataset_path, mode="r") as store: + return { + entity: store[entity] for entity in ENTITY_TABLES if f"/{entity}" in store + } + + +def _degenerate(series: Any) -> bool: + values = series.dropna() + if len(values) == 0 or values.nunique() <= 1: + return True + if values.dtype.kind in "biuf": + return bool((values.astype(float) == 0).all()) + return False + + +def budget_inputs( + pair: CandidatePair, + dataset_path: Path, + *, + model_input_variables: Iterable[str], + critical_inputs: Sequence[str], + accepted_gaps: Mapping[str, str], + previous_missing_inputs: Optional[Sequence[str]], + previous_unusable_critical: Optional[Sequence[str]], + tables: Optional[Mapping[str, Any]] = None, +) -> GateOutcome: + """Critical inputs are present and usable; no input goes newly missing.""" + + tables = dict(tables) if tables is not None else dataset_columns(dataset_path) + columns: dict[str, str] = {} + for entity, table in tables.items(): + for column in table.columns: + columns.setdefault(column, entity) + inputs = set(model_input_variables) + missing = sorted(inputs - set(columns)) + newly_missing = ( + sorted(set(missing) - set(previous_missing_inputs)) + if previous_missing_inputs is not None + else [] + ) + unusable = [] + for name in critical_inputs: + if name not in columns: + unusable.append((name, "missing")) + elif _degenerate(tables[columns[name]][name]): + unusable.append((name, "degenerate")) + previous_bad = set(previous_unusable_critical or []) + regressions = [(n, why) for n, why in unusable if n not in previous_bad] + standing = [(n, why) for n, why in unusable if n in previous_bad] + unaccepted_standing = [(n, why) for n, why in standing if n not in accepted_gaps] + evidence = { + "model_input_variables": len(inputs), + "dataset_columns": len(columns), + "missing_inputs": missing, + "newly_missing_inputs": newly_missing, + "unusable_critical": [list(item) for item in unusable], + "accepted_gaps": dict(accepted_gaps), + } + details = { + "missing_inputs": len(missing), + "newly_missing_inputs": newly_missing, + "unusable_critical": [name for name, _ in unusable], + } + if regressions: + return _result( + "budget_inputs", + "fail", + "Budget-critical inputs became unusable: " + + ", ".join(f"{name} ({why})" for name, why in regressions), + evidence, + details, + ) + if unaccepted_standing or newly_missing: + parts = [] + if newly_missing: + parts.append( + f"{len(newly_missing)} model inputs are newly missing from the data " + f"({', '.join(newly_missing[:8])}{'…' if len(newly_missing) > 8 else ''})" + ) + if unaccepted_standing: + parts.append( + "critical inputs unusable in both pairs: " + + ", ".join(f"{name} ({why})" for name, why in unaccepted_standing) + ) + return _result( + "budget_inputs", "needs_review", "; ".join(parts), evidence, details + ) + return _result( + "budget_inputs", + "pass", + f"All {len(critical_inputs)} critical inputs are present and usable; " + f"no model input is newly missing ({len(missing)} optional inputs absent, as before).", + evidence, + details, + ) + + +# --- 8. Reform contract -------------------------------------------------------- + + +def _load_entrypoint( + entrypoint: str, importer: Callable[[str], Any] +) -> Callable[..., Any]: + module_name, _, attribute = entrypoint.partition(":") + if not attribute: + module_name, _, attribute = entrypoint.rpartition(".") + module = importer(module_name) + function: Callable[..., Any] = getattr(module, attribute) + return function + + +def reform_contract( + *, + entrypoint: Optional[str], + dataset_path: Optional[Path], + seed: int, + max_examples: int, + importer: Callable[[str], Any] = importlib.import_module, +) -> GateOutcome: + """Run the Budget reform contract (W1) and gate on its cases.""" + + if not entrypoint: + return _result( + "reform_contract", + "unavailable", + "No reform contract runner is configured.", + {}, + ) + try: + runner = _load_entrypoint(entrypoint, importer) + except (ImportError, AttributeError) as exc: + return _result( + "reform_contract", + "unavailable", + f"The reform contract runner {entrypoint} is not importable: {exc}", + {"entrypoint": entrypoint}, + ) + try: + report = runner( + routes=None, + dataset_path=str(dataset_path) if dataset_path else None, + seed=seed, + max_examples=max_examples, + ) + except Exception as exc: # the candidate made the contract crash + return _result( + "reform_contract", + "error", + f"The reform contract raised {type(exc).__name__}: {exc}", + {"entrypoint": entrypoint, "traceback": traceback.format_exc()}, + ) + report = json.loads(json.dumps(report, default=str)) + failures, malformed, pending, unsupported = [], [], [], [] + for case in report.get("cases", []): + status = case.get("status") + label = f"{case.get('case_id')}@{case.get('route')}" + if status in ("fail", "error"): + failures.append(label) + elif status == "unsupported": + if not case.get("reason"): + malformed.append(f"{label} is unsupported without a reason") + unsupported.append(label) + elif status == "pending": + if not case.get("decision_id"): + malformed.append(f"{label} is pending without a decision_id") + pending.append(label) + elif status != "pass": + malformed.append(f"{label} has unknown status {status!r}") + for prop in report.get("properties", []): + if prop.get("status") not in ("pass", "pending"): + failures.append(f"property {prop.get('property_id')}") + if not report.get("cases"): + malformed.append("the report has no cases") + details = { + "contract_id": report.get("contract_id"), + "contract_version": report.get("contract_version"), + "report_sha256": evidence_sha256(report), + "pending": pending, + "unsupported": unsupported, + } + if failures: + return _result( + "reform_contract", + "fail", + f"{len(failures)} contract case(s) failed: {', '.join(failures[:8])}", + report, + details, + ) + if malformed: + return _result( + "reform_contract", "error", "; ".join(malformed[:8]), report, details + ) + return _result( + "reform_contract", + "pass", + f"Contract {details['contract_version']}: every case passed" + + (f"; {len(pending)} pending a methodology call" if pending else "") + + (f"; {len(unsupported)} unsupported by design" if unsupported else "") + + ".", + report, + details, + ) + + +# --- 9. Metrics review --------------------------------------------------------- + + +def _metric_key(row: Mapping[str, Any]) -> tuple[str, Optional[int]]: + return (str(row["metric_id"]), row.get("year")) + + +def _bound(bounds: Mapping[str, Any], kind: Optional[str]) -> tuple[float, float]: + spec = (bounds.get("kinds") or {}).get(kind) or bounds.get("default") or {} + return float(spec.get("relative", 0.0)), float(spec.get("absolute", 0.0)) + + +#: Metric-report check prefixes (``identities[].identity_id``) that fail a +#: candidate whatever the previous pair did: none fail on main. +HARD_CHECK_PREFIXES = ("finite:", "weights:", "closure", "identity:", "determinism:") +#: Checks that already fail on main for known model defects (for example +#: ``counted_once:statutory_sick_pay``): they fail a candidate only when the +#: previous certified pair passed them. +REGRESSION_CHECK_PREFIXES = ( + "counted_once:", + "double_count_present:", + "sign:", + "bounds:", + "reform_runs:", +) + + +def classify_check(identity_id: str) -> str: + """``hard``, ``regression`` or ``hard`` for an unknown check (no skips).""" + + if identity_id.startswith(REGRESSION_CHECK_PREFIXES): + return "regression" + return "hard" + + +def compare_metric_reports( + candidate: Mapping[str, Any], + previous: Mapping[str, Any], + bounds: Mapping[str, Any], +) -> tuple[str, str, Evidence]: + """``(status, summary, evidence)`` for a candidate against a previous report. + + Checks (``identities``) follow the metric tool's classification: hard + checks fail outright; known-defect checks fail only as regressions from + the previous pair; ``warn`` is recorded, and a check that newly warns + where the previous pair passed needs review. + """ + + problems: list[str] = [] + review: list[str] = [] + if candidate.get("status") not in (None, "ok"): + problems.append(f"the candidate report status is {candidate.get('status')!r}") + previous_checks = { + str(row.get("identity_id")): row.get("status") + for row in previous.get("identities", []) + } + hard_failures, regressions, preexisting, new_warnings, warnings_ = ( + [], + [], + [], + [], + [], + ) + for row in candidate.get("identities", []): + check_id = str(row.get("identity_id")) + status = row.get("status") + before = previous_checks.get(check_id) + if status == "fail": + if classify_check(check_id) == "hard": + hard_failures.append(check_id) + elif before == "pass" or before is None: + regressions.append(check_id) + else: + preexisting.append(check_id) + elif status == "warn": + warnings_.append(check_id) + if before == "pass": + new_warnings.append(check_id) + if hard_failures: + problems.append(f"checks failed: {', '.join(hard_failures[:8])}") + if regressions: + problems.append( + f"checks the previous pair passed now fail: {', '.join(regressions[:8])}" + ) + if new_warnings: + review.append(f"checks newly warn: {', '.join(new_warnings[:8])}") + if candidate.get("metrics_version") != previous.get("metrics_version"): + problems.append( + "metric definitions differ between the reports " + f"({previous.get('metrics_version')} → {candidate.get('metrics_version')})" + ) + if candidate.get("partition_version") != previous.get("partition_version"): + review.append("the model's fiscal partition changed") + current = {_metric_key(row): row for row in candidate.get("metrics", [])} + before_metrics = {_metric_key(row): row for row in previous.get("metrics", [])} + nonfinite = [ + f"{key[0]} {key[1]}" + for key, row in current.items() + if row.get("value") is None + or not isinstance(row.get("value"), (int, float)) + or not math.isfinite(float(row["value"])) + ] + if nonfinite: + problems.append(f"non-finite values: {', '.join(nonfinite[:8])}") + lost = sorted(f"{key[0]} {key[1]}" for key in set(before_metrics) - set(current)) + if lost: + problems.append(f"metrics disappeared: {', '.join(lost[:8])}") + moves = [] + for key, row in sorted( + current.items(), key=lambda item: (item[0][0], item[0][1] or 0) + ): + old = before_metrics.get(key) + if old is None: + continue + try: + new_value, old_value = float(row["value"]), float(old["value"]) + except (TypeError, ValueError): + continue + if not (math.isfinite(new_value) and math.isfinite(old_value)): + continue + relative, absolute = _bound(bounds, row.get("kind")) + threshold = max(relative * abs(old_value), absolute) + change = new_value - old_value + if abs(change) > threshold: + moves.append( + { + "metric_id": key[0], + "year": key[1], + "kind": row.get("kind"), + "previous": old_value, + "candidate": new_value, + "change": change, + "threshold": threshold, + } + ) + if moves: + review.append(f"{len(moves)} metric move(s) exceed their review bounds") + evidence = { + "metrics_version": candidate.get("metrics_version"), + "partition_version": candidate.get("partition_version"), + "previous_partition_version": previous.get("partition_version"), + "hard_check_failures": hard_failures, + "regressed_checks": regressions, + "preexisting_check_failures": preexisting, + "warn_identities": warnings_, + "new_warnings": new_warnings, + "moves_beyond_bounds": moves, + "candidate_report_sha256": evidence_sha256(candidate), + "previous_report_sha256": evidence_sha256(previous), + } + if problems: + return "fail", "; ".join(problems), evidence + if review: + return "needs_review", "; ".join(review), evidence + note = ( + f" ({len(preexisting)} known check failures carried over)" + if preexisting + else "" + ) + return "pass", f"{len(current)} metrics within their review bounds{note}.", evidence + + +def metrics_review( + *, + candidate_report: Optional[Mapping[str, Any]], + previous_report: Optional[Mapping[str, Any]], + bounds: Mapping[str, Any], + cross_report: Optional[Mapping[str, Any]] = None, + unavailable_reason: Optional[str] = None, +) -> GateOutcome: + """Compare metrics against the previous certificate under review bounds. + + With ``cross_report`` (the candidate model on the previous data), the + change splits into a model-only step (cross against previous) and a + data-only step (candidate against cross); the gate takes the worse. + """ + + if unavailable_reason or candidate_report is None or previous_report is None: + return _result( + "metrics_review", + "unavailable", + unavailable_reason or "Metric reports for both pairs are not available.", + {}, + ) + order = {"pass": 0, "needs_review": 1, "fail": 2} + steps: dict[str, tuple[str, str, Evidence]] = {} + if cross_report is not None: + steps["model_only"] = compare_metric_reports( + cross_report, previous_report, bounds + ) + steps["data_only"] = compare_metric_reports( + candidate_report, cross_report, bounds + ) + else: + steps["total"] = compare_metric_reports( + candidate_report, previous_report, bounds + ) + worst = max(steps.values(), key=lambda step: order[step[0]]) + evidence = {name: step[2] for name, step in steps.items()} + summary = "; ".join(f"{name}: {step[1]}" for name, step in steps.items()) + return _result( + "metrics_review", + worst[0], + summary, + evidence, + details={name: step[0] for name, step in steps.items()}, + ) + + +# --- Metrics tool (W3's aggregate-impact report) --------------------------------- + +VENDORED_TOOL_PACKAGE = "pe_uk_aggregate_impact" +PARTITION_PATH_IN_REPO = "policyengine_uk/data/fiscal_partition.yaml" + +#: Self-contained runner, executed in any environment that has a policyengine +#: release installed (the candidate's, or the previous certified pair's +#: throwaway venv). Arguments: vendor root, JSON settings, output path. +METRICS_RUNNER = """ +import importlib, importlib.util, json, sys +from pathlib import Path +vendor, settings, out = sys.argv[1], json.loads(sys.argv[2]), Path(sys.argv[3]) +sys.path.insert(0, vendor) +api = importlib.import_module("pe_uk_aggregate_impact.api") +partition_module = importlib.import_module("pe_uk_aggregate_impact.partition") +installed = partition_module.default_partition_path() +if installed is not None: + partition_path, source = installed, "installed policyengine_uk" +else: + partition_path, source = Path(vendor) / "fiscal_partition.yaml", "vendored tool commit" +dataset = settings.get("dataset_path") +if not dataset: + from policyengine.provenance.dataset_materialization import materialize_dataset + dataset = materialize_dataset("uk", data_dir=Path(settings["data_dir"])).path +from policyengine_uk import Microsimulation +report = api.compute_budget_metrics( + Microsimulation(dataset=str(dataset)), + years=settings["years"], + partition=partition_module.load_partition(partition_path), + run_guard=settings.get("run_guard", True), + label=settings.get("label", "candidate"), +) +report["partition_source"] = source +report["dataset_path"] = str(dataset) +out.write_text(json.dumps(report)) +""" + + +#: Runner for a pair's input coverage and supported years, in its own +#: environment. It mirrors ``budget_inputs`` and ``supported_years``; a +#: differential test checks they agree. Arguments: JSON settings, output path. +INPUTS_RUNNER = """ +import json, sys +from pathlib import Path +import pandas as pd +settings, out = json.loads(sys.argv[1]), Path(sys.argv[2]) +path = settings.get("dataset_path") +if not path: + from policyengine.provenance.dataset_materialization import materialize_dataset + path = str(materialize_dataset("uk", data_dir=Path(settings["data_dir"])).path) +inputs = settings.get("model_input_variables") +if inputs is None: + from policyengine_uk.system import system + inputs = [name for name, variable in system.variables.items() if variable.is_input_variable()] +inputs = set(inputs) +with pd.HDFStore(path, mode="r") as store: + tables = {e: store[e] for e in ("person", "benunit", "household") if f"/{e}" in store} + first_year = int(str(store["time_period"].iloc[0])[:4]) +columns = {} +for entity, table in tables.items(): + for column in table.columns: + columns.setdefault(column, entity) +def degenerate(series): + values = series.dropna() + if len(values) == 0 or values.nunique() <= 1: + return True + if values.dtype.kind in "biuf": + return bool((values.astype(float) == 0).all()) + return False +unusable = [] +for name in settings["critical"]: + if name not in columns: + unusable.append([name, "missing"]) + elif degenerate(tables[columns[name]][name]): + unusable.append([name, "degenerate"]) +years = settings.get("projected_years") +if years is None: + from policyengine_uk.data.dataset_schema import UKSingleYearDataset + from policyengine_uk.data.economic_assumptions import extend_single_year_dataset + from policyengine_uk.system import system + multi_year = extend_single_year_dataset(UKSingleYearDataset(path), system.parameters) + years = getattr(multi_year, "years", None) + years = years if years is not None else list(multi_year.datasets) +years = sorted(int(y) for y in years) +out.write_text(json.dumps({ + "dataset_path": path, + "missing_inputs": sorted(inputs - set(columns)), + "unusable_critical": unusable, + "supported_years": [y for y in years if y >= first_year], +})) +""" + + +def run_inputs_snapshot( + python: str, + *, + critical: Sequence[str], + out: Path, + dataset_path: Optional[Path] = None, + data_dir: Optional[Path] = None, + model_input_variables: Optional[Sequence[str]] = None, + projected_years: Optional[Sequence[int]] = None, + run: Optional[Callable[..., Any]] = None, +) -> dict[str, Any]: + """Input coverage and supported years of a pair, via ``INPUTS_RUNNER``. + + ``model_input_variables`` and ``projected_years`` default to what the + environment's policyengine-uk reports; tests pass them explicitly. + """ + + import subprocess + + run = run if run is not None else subprocess.run + settings = { + "critical": list(critical), + "dataset_path": str(dataset_path) if dataset_path else None, + "data_dir": str(data_dir) if data_dir else None, + "model_input_variables": ( + list(model_input_variables) if model_input_variables is not None else None + ), + "projected_years": list(projected_years) + if projected_years is not None + else None, + } + run( + [python, "-c", INPUTS_RUNNER, json.dumps(settings), str(out)], + check=True, + cwd=str(out.parent), + ) + snapshot: dict[str, Any] = json.loads(out.read_text()) + return snapshot + + +def vendor_metrics_tool( + tool: Mapping[str, Any], destination: Path, *, get: Callable[..., Any] +) -> Path: + """Copy the metrics tool and its partition from one policyengine-uk commit. + + Returns the directory to put on ``sys.path``; the tool imports as + ``pe_uk_aggregate_impact``. The commit is pinned in the qualification + config so both pairs are measured with the same definitions. + """ + + import tarfile + + repository = tool["repository"] + commit = tool["commit"] + tool_path = tool["path"].rstrip("/") + root = destination / f"metrics-tool-{commit[:12]}" + package = root / VENDORED_TOOL_PACKAGE + if (package / "api.py").exists(): + return root + response = get( + f"https://codeload.github.com/{repository}/tar.gz/{commit}", timeout=120 + ) + response.raise_for_status() + package.mkdir(parents=True, exist_ok=True) + with tarfile.open(fileobj=io.BytesIO(response.content), mode="r:gz") as archive: + for member in archive.getmembers(): + _, _, relative = member.name.partition("/") + if not member.isfile(): + continue + if relative.startswith(tool_path + "/"): + target = package / relative[len(tool_path) + 1 :] + elif relative == PARTITION_PATH_IN_REPO: + target = root / "fiscal_partition.yaml" + else: + continue + if ".." in Path(relative).parts: + raise ValueError(f"Unsafe path in the tool archive: {member.name}") + target.parent.mkdir(parents=True, exist_ok=True) + extracted = archive.extractfile(member) + assert extracted is not None + target.write_bytes(extracted.read()) + if not (package / "api.py").exists(): + raise ValueError(f"{repository}@{commit} has no {tool_path}/api.py.") + return root + + +def run_metrics_report( + python: str, + vendor_root: Path, + *, + years: Sequence[int], + out: Path, + dataset_path: Optional[Path] = None, + data_dir: Optional[Path] = None, + run_guard: bool = True, + label: str = "candidate", + run: Optional[Callable[..., Any]] = None, +) -> dict[str, Any]: + """Compute a metrics report with ``python`` (any environment) via the runner.""" + + import subprocess + + run = run if run is not None else subprocess.run + settings = { + "years": list(years), + "dataset_path": str(dataset_path) if dataset_path else None, + "data_dir": str(data_dir) if data_dir else None, + "run_guard": run_guard, + "label": label, + } + run( + [ + python, + "-c", + METRICS_RUNNER, + str(vendor_root), + json.dumps(settings), + str(out), + ], + check=True, + cwd=str(out.parent), + ) + report: dict[str, Any] = json.loads(out.read_text()) + return report + + +def previous_pair_python( + previous: Mapping[str, Any], + work_dir: Path, + *, + run: Optional[Callable[..., Any]] = None, +) -> str: + """A throwaway venv with the previous certified release installed.""" + + import subprocess + + run = run if run is not None else subprocess.run + venv = work_dir / f"previous-{previous['bundle_version']}" + python = venv / "bin" / "python" + if not python.exists(): + run(["uv", "venv", str(venv), "--python", "3.13"], check=True) + run( + [ + "uv", + "pip", + "install", + "--python", + str(python), + f"policyengine[uk]=={previous['bundle_version']}", + ], + check=True, + ) + return str(python) + + +# --- Orchestration ------------------------------------------------------------- + + +def run_gate(gate_id: str, function: Callable[[], GateOutcome]) -> GateOutcome: + """Run one gate; an unexpected exception becomes an ``error`` result.""" + + try: + return function() + except Exception as exc: + return _result( + gate_id, + "error", + f"The gate raised {type(exc).__name__}: {exc}", + {"traceback": traceback.format_exc()}, + ) + + +def run_gates( + gates: Sequence[tuple[str, Callable[[], GateOutcome]]], +) -> tuple[list[GateResult], dict[str, Evidence]]: + """Run gates in order; always one result per gate, never fewer.""" + + results: list[GateResult] = [] + evidence: dict[str, Evidence] = {} + for gate_id, function in gates: + result, item = run_gate(gate_id, function) + if result.gate_id != gate_id: + result = result.model_copy(update={"gate_id": gate_id}) + results.append(result) + evidence[gate_id] = item + return results, evidence + + +def _download(url: str, destination: Path, *, get: Callable[..., Any]) -> Path: + destination.parent.mkdir(parents=True, exist_ok=True) + with get(url, stream=True, timeout=120) as response: + response.raise_for_status() + with destination.open("wb") as stream: + for chunk in response.iter_content(chunk_size=1 << 20): + stream.write(chunk) + return destination + + +def _previous_gate_evidence( + ledger_root: Optional[Path], previous: Optional[Mapping[str, Any]] +) -> dict[str, Any]: + """Evidence the previous certificate's qualification recorded, if any.""" + + if ledger_root is None or not previous: + return {} + base = ledger_root / "uk" + if not base.is_dir(): + return {} + for receipt_path in base.glob("*/qualification_receipt.json"): + receipt = json.loads(receipt_path.read_text()) + pair = receipt.get("pair", {}) + if ( + pair.get("model", {}).get("version") == previous.get("model_version") + and pair.get("data", {}).get("release_version") + == previous.get("data_release_version") + and receipt.get("verdict") in ("qualified", "needs_review") + ): + found: dict[str, Any] = {} + attempts = sorted((receipt_path.parent / "attempts").glob("*/gates")) + if attempts: + for name in ("supported_years", "budget_inputs"): + path = attempts[-1] / f"{name}.json" + if path.exists(): + found[name] = json.loads(path.read_text()) + return found + return {} + + +def run_candidate_gates( + resolved: Any, + harness: QualificationHarness, + *, + config: Mapping[str, Any], + work_dir: Path, + previous_certificate: Optional[Mapping[str, Any]], + ledger_root: Optional[Path], +) -> tuple[list[GateResult], dict[str, Evidence]]: + """Run gates 1–9 on the installed candidate, with real I/O.""" + + import os + + import requests + + from policyengine.provenance.dataset_materialization import materialize_dataset + + pair: CandidatePair = resolved.pair + work_dir.mkdir(parents=True, exist_ok=True) + data_dir = Path(config.get("data_dir") or work_dir / "data") + qualification_dir = Path(__file__).resolve().parents[1] / "data" / "qualification" + previous_evidence = _previous_gate_evidence(ledger_root, previous_certificate) + critical_spec = json.loads( + (qualification_dir / config["budget_inputs"]["critical"]).read_text() + ) + token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN") + state: dict[str, Any] = {} + + def dataset() -> Path: + if "dataset" not in state: + source = materialize_dataset("uk", data_dir=data_dir) + state["dataset"] = Path(source.path) + path: Path = state["dataset"] + return path + + def gate_wheels() -> GateOutcome: + paths = {} + for package, wheel in ( + (pair.model, resolved.model_wheel), + (pair.core, resolved.core_wheel), + ): + paths[package.name] = _download( + wheel.url, work_dir / "wheels" / wheel.filename, get=requests.get + ) + return wheel_hashes( + pair, + wheel_paths=paths, + pypi_digests={ + pair.model.name: resolved.model_wheel.sha256, + pair.core.name: resolved.core_wheel.sha256, + }, + ) + + def gate_core() -> GateOutcome: + if "manifest" not in state: + return _result( + "core_compatibility", + "error", + "The release manifest was not read (data_access did not succeed).", + {}, + ) + return core_compatibility( + pair, state["manifest"], model_requires_core=resolved.model_requires_core + ) + + def gate_data_access() -> GateOutcome: + result, evidence, manifest = data_access( + pair, get=requests.get, head=requests.head, token=token + ) + if manifest is not None: + state["manifest"] = manifest + return result, evidence + + def previous_snapshot() -> Optional[dict[str, Any]]: + """The previous pair's inputs and years: from the ledger, else computed.""" + + if "previous_snapshot" in state: + cached: Optional[dict[str, Any]] = state["previous_snapshot"] + return cached + snapshot: Optional[dict[str, Any]] = None + recorded_inputs = previous_evidence.get("budget_inputs") + recorded_years = previous_evidence.get("supported_years") + if recorded_inputs and recorded_years: + snapshot = { + "missing_inputs": recorded_inputs.get("missing_inputs"), + "unusable_critical": recorded_inputs.get("unusable_critical", []), + "supported_years": recorded_years.get("supported_years"), + "source": "ledger", + } + elif previous_certificate: + snapshot = run_inputs_snapshot( + previous_pair_python(previous_certificate, work_dir), + critical=critical_spec["critical"], + out=work_dir / "previous-inputs.json", + data_dir=work_dir / "previous-data", + ) + snapshot["source"] = ( + f"computed with policyengine {previous_certificate['bundle_version']}" + ) + state["previous_snapshot"] = snapshot + return snapshot + + def gate_years() -> GateOutcome: + previous = previous_snapshot() + previous_years = previous.get("supported_years") if previous else None + return supported_years( + pair, + dataset(), + required_years=config["required_years"], + budget_horizon_years=config["budget_horizon_years"], + previous_supported_years=previous_years, + ) + + def gate_inputs() -> GateOutcome: + from policyengine_uk.system import system + + previous = previous_snapshot() + result, evidence = budget_inputs( + pair, + dataset(), + model_input_variables=[ + name + for name, variable in system.variables.items() + if variable.is_input_variable() + ], + critical_inputs=critical_spec["critical"], + accepted_gaps=critical_spec.get("accepted_gaps", {}), + previous_missing_inputs=previous.get("missing_inputs") + if previous + else None, + previous_unusable_critical=( + [item[0] for item in previous.get("unusable_critical", [])] + if previous + else None + ), + ) + evidence["previous_source"] = previous.get("source") if previous else None + return result, evidence + + def gate_contract() -> GateOutcome: + settings = config["reform_contract"] + return reform_contract( + entrypoint=settings.get("entrypoint"), + dataset_path=dataset(), + seed=int(settings.get("seed", 0)), + max_examples=int(settings.get("max_examples", 50)), + ) + + def gate_metrics() -> GateOutcome: + import sys + + settings = config["metrics"] + tool = settings.get("tool") + if not tool: + return metrics_review( + candidate_report=None, + previous_report=None, + bounds={}, + unavailable_reason="No metrics tool commit is configured (metrics.tool).", + ) + if not previous_certificate: + return metrics_review( + candidate_report=None, + previous_report=None, + bounds={}, + unavailable_reason="No previous certificate to compare against.", + ) + bounds = json.loads((qualification_dir / settings["bounds"]).read_text()) + vendor_root = vendor_metrics_tool(tool, work_dir, get=requests.get) + years = settings["years"] + candidate_report = run_metrics_report( + sys.executable, + vendor_root, + years=years, + out=work_dir / "metrics-candidate.json", + dataset_path=dataset(), + label="candidate", + ) + previous_report = run_metrics_report( + previous_pair_python(previous_certificate, work_dir), + vendor_root, + years=years, + out=work_dir / "metrics-previous.json", + data_dir=work_dir / "previous-data", + label="previous", + ) + cross_report = None + if previous_certificate.get("dataset_sha256") != pair.data.dataset_sha256: + cross_report = run_metrics_report( + sys.executable, + vendor_root, + years=years, + out=work_dir / "metrics-candidate-model-previous-data.json", + dataset_path=Path(previous_report["dataset_path"]), + label="candidate model, previous data", + ) + state["metrics_reports"] = { + "candidate": candidate_report, + "previous": previous_report, + "candidate_model_previous_data": cross_report, + } + result, evidence = metrics_review( + candidate_report=candidate_report, + previous_report=previous_report, + bounds=bounds, + cross_report=cross_report, + ) + evidence["tool"] = dict(tool) + evidence["partition_sources"] = { + "candidate": candidate_report.get("partition_source"), + "previous": previous_report.get("partition_source"), + } + return result, evidence + + gates = [ + ("installed_versions", lambda: installed_versions(pair, harness)), + ("wheel_hashes", gate_wheels), + ("data_access", gate_data_access), + ("core_compatibility", gate_core), + ("dataset_bytes", lambda: dataset_bytes(pair, dataset())), + ("supported_years", gate_years), + ("budget_inputs", gate_inputs), + ("reform_contract", gate_contract), + ("metrics_review", gate_metrics), + ] + results, evidence = run_gates(gates) + for name, report in (state.get("metrics_reports") or {}).items(): + if report is not None: + evidence[f"metrics_report_{name}"] = report + return results, evidence + + +def version_sort_key(version: str) -> Version: + return Version(version) diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py new file mode 100644 index 00000000..a8261556 --- /dev/null +++ b/src/policyengine/provenance/uk_qualification.py @@ -0,0 +1,1072 @@ +"""Orchestration for qualifying a UK model/data candidate. + +``scripts/check_uk_candidate.py`` is the command-line front end and +``.github/workflows/certify-uk-release.yaml`` runs it. The steps are: + +``resolve`` + Find the candidate pair: the newest (or requested) policyengine-uk wheel + from PyPI, the core it needs, and the newest (or requested) uk-data + release at the data repository's current manifest revision. Decide + whether to qualify it, or whether it is already certified, stale, or a + duplicate of an attempt in the ledger. +``prepare`` + On a checkout of ``main``, certify the pair into the bundle manifest + (exact ``==`` claim backed by the pair id when no publisher claim covers + it), regenerate pins, ``uv.lock``, TROs, the certified-version test + constants and household snapshots together, and commit that as the + candidate commit on ``candidate/uk/-``. +``gates`` + Run the mandatory local gates on the candidate commit + (:mod:`policyengine.provenance.uk_candidate`). +``request-replay`` / ``poll-replay`` + Send the scorecard an immutable replay request naming the candidate + commit, and read back its terminal status and receipt. +``finalize`` + Record the qualification receipt in the ledger. +``promote`` + Pick the newest promotable pair that advances ``main`` and mark its + candidate PR ready, closing superseded candidates. + +Network, git and GitHub access are injected so every decision can be tested +offline. +""" + +from __future__ import annotations + +import hashlib +import json +import os +import re +import subprocess +from collections.abc import Callable, Iterable, Mapping, Sequence +from dataclasses import dataclass, field +from pathlib import Path +from typing import Any, Literal, Optional + +from packaging.requirements import Requirement +from packaging.specifiers import SpecifierSet +from packaging.version import InvalidVersion, Version + +from policyengine.provenance.manifest import DataReleaseManifest +from policyengine.provenance.qualification import ( + REQUIRED_GATES, + CandidatePair, + GateResult, + IssuedBy, + PinnedData, + PinnedWheel, + PreviousCertificate, + QualificationHarness, + QualificationReceipt, + ReplayQualificationRequest, + ReplayReceipt, + ReplayReference, + ReplayStatus, + ReviewAcceptance, + dominates, + evaluate_replay_receipt, + qualification_verdict, + replay_gate_while_pending, + select_promotion_target, +) +from policyengine.provenance.qualification_ledger import ( + attempt_directory, + pair_directory, + read_json, + write_json, +) +from policyengine.provenance.receipt import certificate_sha256 + +UK_MODEL_PACKAGE = "policyengine-uk" +CORE_PACKAGE = "policyengine-core" +UK_DATA_REPO_ID = "policyengine/policyengine-uk-data-private" +UK_DATA_REPO_TYPE: Literal["model"] = "model" +TOKEN_VARIABLES = ("HF_TOKEN", "HUGGING_FACE_TOKEN", "HUGGINGFACE_HUB_TOKEN") +REPO_ROOT = Path(__file__).resolve().parents[3] + +Action = Literal["qualify", "already_certified", "stale", "duplicate"] + + +# --- Resolution ------------------------------------------------------------ + + +@dataclass(frozen=True) +class WheelFile: + filename: str + url: str + sha256: str + + +@dataclass(frozen=True) +class ResolvedCandidate: + """A candidate pair plus what is needed to fetch and certify it.""" + + pair: CandidatePair + model_wheel: WheelFile + core_wheel: WheelFile + manifest_uri: str + model_requires_core: str + + +def _stable_versions( + releases: Mapping[str, Sequence[Mapping[str, Any]]], +) -> list[Version]: + versions = [] + for text, files in releases.items(): + try: + version = Version(text) + except InvalidVersion: + continue + if version.is_prerelease or version.is_devrelease: + continue + if not files or all(item.get("yanked") for item in files): + continue + versions.append(version) + return sorted(versions) + + +def _wheel(files: Sequence[Mapping[str, Any]], name: str, version: str) -> WheelFile: + wheels = [ + item + for item in files + if item.get("packagetype") == "bdist_wheel" and not item.get("yanked") + ] + if len(wheels) != 1: + raise ValueError( + f"{name} {version} must publish exactly one wheel; found {len(wheels)}." + ) + entry = wheels[0] + return WheelFile( + filename=entry["filename"], url=entry["url"], sha256=entry["digests"]["sha256"] + ) + + +def core_requirement(requires_dist: Iterable[str]) -> str: + """The model's ``policyengine-core`` specifier (unconditional requirements).""" + + for line in requires_dist or (): + requirement = Requirement(line) + if requirement.name.lower().replace("_", "-") != CORE_PACKAGE: + continue + if requirement.marker is not None and not requirement.marker.evaluate(): + continue + return str(requirement.specifier) + raise ValueError("policyengine-uk declares no policyengine-core requirement.") + + +def choose_core_version( + current_core: str, + specifier: str, + available: Sequence[Version], +) -> str: + """Keep the certified core if the model accepts it; else the newest accepted.""" + + spec = SpecifierSet(specifier) + if Version(current_core) in spec: + return current_core + accepted = [version for version in available if version in spec] + if not accepted: + raise ValueError( + f"No published policyengine-core release satisfies {specifier}." + ) + return str(max(accepted)) + + +def latest_data_release(tags: Iterable[str]) -> str: + """The newest release tag that is a plain version (``1.58.0``).""" + + versions = [] + for tag in tags: + if not re.fullmatch(r"\d+(\.\d+)*", tag): + continue + versions.append(Version(tag)) + if not versions: + raise ValueError("The data repository has no version tags.") + return str(max(versions)) + + +def resolve_candidate( + *, + current_core: str, + pypi_project: Callable[[str], Mapping[str, Any]], + hf_revision_sha: Callable[[str, str], str], + hf_tags: Callable[[str], Sequence[str]], + hf_file: Callable[[str, str, str], bytes], + model_version: Optional[str] = None, + data_version: Optional[str] = None, +) -> ResolvedCandidate: + """Resolve the candidate pair from PyPI and Hugging Face.""" + + model_project = pypi_project(UK_MODEL_PACKAGE) + releases = model_project["releases"] + model_version = model_version or str(_stable_versions(releases)[-1]) + if model_version not in releases: + raise ValueError(f"{UK_MODEL_PACKAGE} {model_version} is not on PyPI.") + model_wheel = _wheel(releases[model_version], UK_MODEL_PACKAGE, model_version) + model_release = pypi_project(f"{UK_MODEL_PACKAGE}/{model_version}") + requires_core = core_requirement(model_release["info"].get("requires_dist") or []) + + core_project = pypi_project(CORE_PACKAGE) + core_version = choose_core_version( + current_core, requires_core, _stable_versions(core_project["releases"]) + ) + core_wheel = _wheel( + core_project["releases"][core_version], CORE_PACKAGE, core_version + ) + + data_version = data_version or latest_data_release(hf_tags(UK_DATA_REPO_ID)) + manifest_revision = hf_revision_sha(UK_DATA_REPO_ID, "main") + manifest_path = f"releases/{data_version}/release_manifest.json" + manifest_bytes = hf_file(UK_DATA_REPO_ID, manifest_revision, manifest_path) + manifest = DataReleaseManifest.model_validate_json(manifest_bytes) + if manifest.data_package.version != data_version: + raise ValueError( + f"{manifest_path} describes {manifest.data_package.version}, not {data_version}." + ) + dataset = manifest.default_datasets.get("national") + if dataset is None or dataset not in manifest.artifacts: + raise ValueError( + f"uk-data {data_version} declares no national default dataset." + ) + artifact = manifest.artifacts[dataset] + if not artifact.sha256 or not artifact.size_bytes: + raise ValueError(f"uk-data {data_version} {dataset} has no sha256 or size.") + build_id = ( + manifest.build.build_id if manifest.build and manifest.build.build_id else None + ) + if build_id is None: + raise ValueError(f"uk-data {data_version} records no build id.") + + pair = CandidatePair( + country_id="uk", + model=PinnedWheel( + name=UK_MODEL_PACKAGE, + version=model_version, + wheel_sha256=model_wheel.sha256, + ), + core=PinnedWheel( + name=CORE_PACKAGE, version=core_version, wheel_sha256=core_wheel.sha256 + ), + data=PinnedData( + data_package=manifest.data_package.name, + release_version=data_version, + build_id=build_id, + repo_id=UK_DATA_REPO_ID, + repo_type=UK_DATA_REPO_TYPE, + release_manifest_path=manifest_path, + release_manifest_revision=manifest_revision, + release_manifest_sha256=hashlib.sha256(manifest_bytes).hexdigest(), + dataset=dataset, + dataset_path=artifact.path, + dataset_revision=artifact.revision, + dataset_sha256=artifact.sha256, + size_bytes=artifact.size_bytes, + ), + ) + return ResolvedCandidate( + pair=pair, + model_wheel=model_wheel, + core_wheel=core_wheel, + manifest_uri=( + f"hf://{UK_DATA_REPO_TYPE}/{UK_DATA_REPO_ID}@{manifest_revision}/{manifest_path}" + ), + model_requires_core=requires_core, + ) + + +# --- Deciding what to do ------------------------------------------------------ + + +def certified_order_key(bundle: Mapping[str, Any]) -> tuple[str, str, str]: + """(model version, data release, core version) certified on a branch.""" + + record = bundle["data_releases"]["uk"] + return ( + record["model_package"]["version"], + record["data_package"]["version"], + bundle["packages"][CORE_PACKAGE]["version"], + ) + + +def previous_certificate(bundle: Mapping[str, Any]) -> PreviousCertificate: + record = bundle["data_releases"]["uk"] + return PreviousCertificate( + bundle_version=bundle["policyengine_version"], + model_version=record["model_package"]["version"], + core_version=bundle["packages"][CORE_PACKAGE]["version"], + data_release_version=record["data_package"]["version"], + dataset_sha256=record["certified_data_artifact"]["sha256"], + certificate_sha256=certificate_sha256(record), + ) + + +def candidate_action( + pair: CandidatePair, + bundle: Mapping[str, Any], + ledger_root: Optional[Path], + *, + base_commit: str, + force: bool = False, +) -> tuple[Action, str]: + """Whether to qualify ``pair`` now, and why.""" + + current = certified_order_key(bundle) + record = bundle["data_releases"]["uk"] + if pair.order_key == current and ( + record["certified_data_artifact"]["sha256"] == pair.data.dataset_sha256 + ): + return "already_certified", f"{current} is already certified on main" + if dominates(current, pair.order_key): + return "stale", f"main certifies {current}, newer than {pair.order_key}" + if force or ledger_root is None: + return "qualify", "forced" if force else "no ledger" + pair_dir = pair_directory(ledger_root, "uk", pair.pair_id) + latest = pair_dir / "qualification_receipt.json" + if latest.exists(): + receipt = QualificationReceipt.model_validate(read_json(latest)) + if receipt.verdict != "incomplete": + return "duplicate", f"pair already {receipt.verdict} in the ledger" + attempt = attempt_directory(ledger_root, "uk", pair.pair_id, base_commit[:12]) + if attempt.exists(): + return "duplicate", f"an attempt from base {base_commit[:12]} exists" + return "qualify", "new pair, or an incomplete pair on a new base commit" + + +# --- Preparing the candidate commit ----------------------------------------- + +#: Test files that pin the certified UK pair literally. Promotion regenerates +#: them with the rest of the certification so the suite tests the new pair. +CERTIFIED_CONSTANT_FILES = ( + "tests/test_models.py", + "tests/test_release_manifests.py", + "tests/test_uk_regions.py", +) + + +def certified_constant_replacements( + old_record: Mapping[str, Any], new_record: Mapping[str, Any] +) -> list[tuple[str, str]]: + """Exact quoted-literal replacements from the old to the new certificate.""" + + def values(record: Mapping[str, Any]) -> dict[str, Optional[str]]: + certification = record.get("certification") or {} + data = record.get("data_package") or {} + return { + "model": (record.get("model_package") or {}).get("version"), + "built_with": certification.get("built_with_model_version"), + "data": data.get("version"), + "build_id": certification.get("data_build_id"), + "revision": data.get("release_manifest_revision"), + } + + old, new = values(old_record), values(new_record) + pairs: list[tuple[str, str]] = [] + for key in ("build_id", "revision", "model", "built_with", "data"): + before, after = old[key], new[key] + if before and after and before != after: + pairs.append((before, after)) + return pairs + + +def rewrite_certified_constants( + repo_root: Path, replacements: Sequence[tuple[str, str]] +) -> list[str]: + """Rewrite quoted occurrences of old certified values in the constant files. + + Only string-literal occurrences change: ``"2.125.1"``, ``"@1.58.0"``, + ``"releases/1.58.0/release_manifest.json"`` and URIs ending ``@1.58.0``. + Returns the files changed. + """ + + changed = [] + for relative in CERTIFIED_CONSTANT_FILES: + path = repo_root / relative + text = path.read_text() + updated = text + for old, new in replacements: + pattern = re.compile( + r'(?P
["@/-])' + re.escape(old) + r'(?P["/])'
+            )
+            updated = pattern.sub(
+                lambda m: m.group("pre") + new + m.group("post"), updated
+            )
+        if updated != text:
+            path.write_text(updated)
+            changed.append(relative)
+    return changed
+
+
+def candidate_branch(pair: CandidatePair) -> str:
+    return f"candidate/uk/{pair.model.version}-{pair.data.release_version}"
+
+
+def changelog_fragment(pair: CandidatePair, basis_note: str) -> str:
+    return (
+        f"Certify uk-data {pair.data.release_version} (`{pair.data.dataset}`) with "
+        f"policyengine-uk {pair.model.version} and policyengine-core "
+        f"{pair.core.version}, qualified automatically as pair "
+        f"`{pair.pair_id[:12]}`. {basis_note}\n"
+    )
+
+
+Runner = Callable[..., subprocess.CompletedProcess]
+
+
+def _run(
+    command: Sequence[str], *, cwd: Path, env: Optional[Mapping[str, str]] = None
+) -> subprocess.CompletedProcess:
+    return subprocess.run(
+        list(command), cwd=cwd, env=dict(env) if env is not None else None, check=True
+    )
+
+
+def prepare_candidate_commit(
+    repo_root: Path,
+    resolved: ResolvedCandidate,
+    *,
+    python: str,
+    run: Runner = _run,
+    refresh_snapshots: bool = True,
+) -> dict[str, Any]:
+    """Certify the pair into the working tree and regenerate everything with it.
+
+    The working tree must be a clean checkout of the base commit on the
+    candidate branch. Returns what changed; the caller commits it.
+    """
+
+    pair = resolved.pair
+    bundle_path = (
+        repo_root / "src" / "policyengine" / "data" / "bundle" / "manifest.json"
+    )
+    old_record = json.loads(bundle_path.read_text())["data_releases"]["uk"]
+    run(
+        [
+            python,
+            "scripts/bundle.py",
+            "certify-data",
+            "--country",
+            "uk",
+            "--data-producer",
+            "populace",
+            "--manifest-uri",
+            resolved.manifest_uri,
+            "--model-version",
+            pair.model.version,
+            "--core-version",
+            pair.core.version,
+            "--qualified-pair-id",
+            pair.pair_id,
+            "--no-changelog",
+        ],
+        cwd=repo_root,
+    )
+    new_bundle = json.loads(bundle_path.read_text())
+    new_record = new_bundle["data_releases"]["uk"]
+    if new_record["model_package"].get("sha256") != pair.model.wheel_sha256:
+        raise ValueError("The certified model wheel hash differs from the candidate's.")
+    if new_record["certified_data_artifact"].get("sha256") != pair.data.dataset_sha256:
+        raise ValueError("The certified dataset hash differs from the candidate's.")
+    run(
+        [
+            "uv",
+            "lock",
+            "--no-config",
+            "--no-sources",
+            "--default-index",
+            "https://pypi.org/simple",
+            "--python",
+            python,
+        ],
+        cwd=repo_root,
+    )
+    run([python, "scripts/release_lock.py"], cwd=repo_root)
+    run(
+        [python, "scripts/bundle.py", "generate", "--include-tros", "--strict-tros"],
+        cwd=repo_root,
+    )
+    constants = rewrite_certified_constants(
+        repo_root, certified_constant_replacements(old_record, new_record)
+    )
+    basis = new_record["certification"]["compatibility_basis"]
+    basis_note = {
+        "built_with_model_package": "The data was built with this model version.",
+        "legacy_compatible_model_package": "The data publisher's compatibility claim covers this model version.",
+        "qualified_exact_pair": "No publisher claim covers this model version, so the certificate is an exact claim backed by the qualification receipt.",
+    }.get(basis, f"Compatibility basis: {basis}.")
+    fragment = (
+        repo_root
+        / "changelog.d"
+        / (f"certify-uk-{pair.model.version}-{pair.data.release_version}.changed.md")
+    )
+    fragment.write_text(changelog_fragment(pair, basis_note))
+    if refresh_snapshots:
+        run(
+            [
+                python,
+                "-m",
+                "pytest",
+                "tests/test_household_calculator_snapshot.py",
+                "-q",
+            ],
+            cwd=repo_root,
+            env={**os.environ, "PE_UPDATE_SNAPSHOTS": "1"},
+        )
+    run(
+        [python, "scripts/bundle.py", "check", "--include-tros", "--strict-tros"],
+        cwd=repo_root,
+    )
+    return {
+        "compatibility_basis": basis,
+        "constant_files": constants,
+        "changelog_fragment": str(fragment.relative_to(repo_root)),
+    }
+
+
+def packaged_manifest_sha256(repo_root: Path) -> str:
+    path = repo_root / "src" / "policyengine" / "data" / "bundle" / "manifest.json"
+    return hashlib.sha256(path.read_bytes()).hexdigest()
+
+
+# --- Replay request -------------------------------------------------------
+
+
+def expected_release_bundle(python: str, *, cwd: Path) -> dict[str, Optional[str]]:
+    """``dict(pe.uk.uk_latest.release_bundle)`` under packaged certification.
+
+    Runs in a subprocess with every Hugging Face token removed, as the
+    scorecard does, so the bundled certification is what is reported.
+    """
+
+    env = {
+        key: value for key, value in os.environ.items() if key not in TOKEN_VARIABLES
+    }
+    output = subprocess.run(
+        [
+            python,
+            "-c",
+            "import json, policyengine as pe; "
+            "print(json.dumps(dict(pe.uk.uk_latest.release_bundle), sort_keys=True))",
+        ],
+        cwd=cwd,
+        env=env,
+        check=True,
+        capture_output=True,
+        text=True,
+    ).stdout
+    bundle: dict[str, Optional[str]] = json.loads(output.strip().splitlines()[-1])
+    return bundle
+
+
+def build_replay_request(
+    pair: CandidatePair,
+    harness: QualificationHarness,
+    *,
+    release_bundle: Mapping[str, Optional[str]],
+    issued_by: IssuedBy,
+    attempt: int = 1,
+    compare_to: str = "latest_certified",
+) -> ReplayQualificationRequest:
+    """The immutable pre-promotion request for the scorecard."""
+
+    return ReplayQualificationRequest.model_validate(
+        {
+            "schema": "policyengine.uk-replay-qualification-request/v1",
+            "kind": "candidate",
+            "attempt": attempt,
+            "candidate": {
+                "policyengine": {
+                    "version": harness.policyengine_version,
+                    "source": {
+                        "git": {
+                            "repository": "PolicyEngine/policyengine.py",
+                            "commit": harness.git_commit,
+                        }
+                    },
+                    "packaged_bundle_manifest_sha256": harness.packaged_bundle_manifest_sha256,
+                },
+                "policyengine_uk": {
+                    "version": pair.model.version,
+                    "wheel_sha256": pair.model.wheel_sha256,
+                },
+                "policyengine_core": {
+                    "version": pair.core.version,
+                    "wheel_sha256": pair.core.wheel_sha256,
+                },
+                "data": {
+                    "build_id": pair.data.build_id,
+                    "dataset": pair.data.dataset,
+                    "repo_id": pair.data.repo_id,
+                    "repo_type": pair.data.repo_type,
+                    "revision": pair.data.dataset_revision,
+                    "path": pair.data.dataset_path,
+                    "sha256": pair.data.dataset_sha256,
+                    "size_bytes": pair.data.size_bytes,
+                    "release_manifest_sha256": pair.data.release_manifest_sha256,
+                },
+                "expected_release_bundle": dict(release_bundle),
+            },
+            "compare_to": compare_to,
+            "requested_by": {
+                "repository": issued_by.repository,
+                "workflow_run_id": issued_by.workflow_run_id,
+                "run_attempt": issued_by.run_attempt,
+                "commit": harness.git_commit,
+                "pair_id": pair.pair_id,
+            },
+        }
+    )
+
+
+def replay_dispatch_payload(
+    request: ReplayQualificationRequest, *, event_type: str
+) -> dict[str, Any]:
+    return {"event_type": event_type, "client_payload": {"request": request.document()}}
+
+
+def replay_state_paths(request_id: str) -> tuple[str, str]:
+    base = f"requests/{request_id}"
+    return f"{base}/STATUS.json", f"{base}/REPLAY_RECEIPT.json"
+
+
+def read_replay(
+    request: ReplayQualificationRequest,
+    *,
+    fetch: Callable[[str, str], Optional[bytes]],
+    state_ref: str,
+) -> tuple[GateResult, Optional[ReplayStatus], Optional[ReplayReceipt]]:
+    """Read the scorecard's status and, when terminal, its receipt.
+
+    ``fetch(ref, path)`` returns file bytes from the scorecard repository at
+    a ref or commit, or ``None`` if absent.
+    """
+
+    status_path, receipt_path = replay_state_paths(request.request_id)
+    raw_status = fetch(state_ref, status_path)
+    if raw_status is None:
+        return replay_gate_while_pending(None), None, None
+    status = ReplayStatus.model_validate_json(raw_status)
+    if not status.terminal:
+        return replay_gate_while_pending(status), status, None
+    assert status.receipt_commit is not None
+    raw_receipt = fetch(status.receipt_commit, receipt_path)
+    if raw_receipt is None:
+        return (
+            GateResult(
+                gate_id="replay",
+                status="fail",
+                summary=(
+                    f"Status names receipt commit {status.receipt_commit}, which has "
+                    "no REPLAY_RECEIPT.json."
+                ),
+            ),
+            status,
+            None,
+        )
+    receipt = ReplayReceipt.from_document(json.loads(raw_receipt))
+    return evaluate_replay_receipt(request, status, receipt), status, receipt
+
+
+# --- Finalizing ---------------------------------------------------------------
+
+
+def assemble_receipt(
+    pair: CandidatePair,
+    harness: QualificationHarness,
+    gates: Sequence[GateResult],
+    *,
+    issued_by: IssuedBy,
+    completed_at: str,
+    previous: Optional[PreviousCertificate],
+    replay: Optional[ReplayReference],
+) -> QualificationReceipt:
+    """A receipt whose verdict follows from the gates; missing gates count as missing."""
+
+    ordered = sorted(
+        gates,
+        key=lambda gate: (
+            REQUIRED_GATES.index(gate.gate_id)
+            if gate.gate_id in REQUIRED_GATES
+            else len(REQUIRED_GATES),
+            gate.gate_id,
+        ),
+    )
+    return QualificationReceipt(
+        schema_version=1,
+        receipt_type="policyengine.candidate_qualification_receipt",
+        pair_id=pair.pair_id,
+        pair=pair,
+        harness=harness,
+        previous_certificate=previous,
+        replay=replay,
+        gates=list(ordered),
+        verdict=qualification_verdict(ordered),
+        issued_by=issued_by,
+        completed_at=completed_at,
+    )
+
+
+def accept_review(
+    receipt: QualificationReceipt,
+    *,
+    reviewer: str,
+    accepted_receipt_sha256: str,
+    explanation: str,
+    accepted_at: str,
+) -> QualificationReceipt:
+    """Attach a reviewer's acceptance of exactly this needs-review receipt."""
+
+    if receipt.verdict != "needs_review":
+        raise ValueError(
+            f"Only needs-review receipts can be accepted, not {receipt.verdict}."
+        )
+    if accepted_receipt_sha256 != receipt.unreviewed_sha256:
+        raise ValueError(
+            "The acceptance names different receipt bytes "
+            f"({accepted_receipt_sha256}, current {receipt.unreviewed_sha256})."
+        )
+    return receipt.model_copy(
+        update={
+            "review": ReviewAcceptance(
+                reviewer=reviewer,
+                accepted_at=accepted_at,
+                accepted_receipt_sha256=accepted_receipt_sha256,
+                explanation=explanation,
+            )
+        }
+    )
+
+
+# --- Attempt directories -----------------------------------------------------
+#
+# Every step of an attempt reads and writes one directory inside the ledger
+# checkout (``//attempts//``), so a
+# scheduled catch-up can finish an attempt whose replay outlasted its job with
+# exactly the code path the job would have run.
+
+
+def stage_attempt(
+    attempt_dir: Path,
+    candidate_payload: Mapping[str, Any],
+    harness: QualificationHarness,
+) -> None:
+    write_json(attempt_dir / "candidate.json", dict(candidate_payload))
+    write_json(attempt_dir / "harness.json", harness.canonical_payload())
+
+
+def write_gate_results(
+    attempt_dir: Path, results: Sequence[GateResult], evidence: Mapping[str, Any]
+) -> None:
+    for result in results:
+        write_json(
+            attempt_dir / "gates" / f"{result.gate_id}.result.json",
+            result.canonical_payload(),
+        )
+    for gate_id, item in evidence.items():
+        write_json(attempt_dir / "gates" / f"{gate_id}.json", item)
+
+
+def load_gate_results(attempt_dir: Path) -> list[GateResult]:
+    results = [
+        GateResult.model_validate(read_json(path))
+        for path in sorted((attempt_dir / "gates").glob("*.result.json"))
+    ]
+    replay = attempt_dir / "replay" / "replay.result.json"
+    if replay.exists():
+        results = [gate for gate in results if gate.gate_id != "replay"]
+        results.append(GateResult.model_validate(read_json(replay)))
+    return results
+
+
+def finalize_attempt(
+    attempt_dir: Path,
+    ledger_root: Path,
+    *,
+    issued_by: IssuedBy,
+    completed_at: str,
+) -> QualificationReceipt:
+    """Assemble and record the receipt for a staged attempt."""
+
+    candidate = read_json(attempt_dir / "candidate.json")
+    pair = CandidatePair.model_validate(candidate["pair"])
+    harness = QualificationHarness.model_validate(
+        read_json(attempt_dir / "harness.json")
+    )
+    gates = load_gate_results(attempt_dir)
+    if not any(gate.gate_id == "replay" for gate in gates):
+        gates.append(replay_gate_while_pending(None))
+    previous = (
+        PreviousCertificate.model_validate(candidate["previous_certificate"])
+        if candidate.get("previous_certificate")
+        else None
+    )
+    replay_reference = None
+    request_path = attempt_dir / "replay" / "request.json"
+    if request_path.exists():
+        request = ReplayQualificationRequest.model_validate(read_json(request_path))
+        status_path = attempt_dir / "replay" / "status.json"
+        status = (
+            ReplayStatus.model_validate(read_json(status_path))
+            if status_path.exists()
+            else None
+        )
+        replay_reference = ReplayReference(
+            request_id=request.request_id,
+            receipt_sha256=status.receipt_sha256 if status else None,
+            receipt_commit=status.receipt_commit if status else None,
+        )
+    receipt = assemble_receipt(
+        pair,
+        harness,
+        gates,
+        issued_by=issued_by,
+        completed_at=completed_at,
+        previous=previous,
+        replay=replay_reference,
+    )
+    write_json(attempt_dir / "qualification_receipt.json", receipt.canonical_payload())
+    pair_dir = pair_directory(ledger_root, "uk", pair.pair_id)
+    write_json(pair_dir / "pair.json", pair.canonical_payload())
+    write_json(pair_dir / "qualification_receipt.json", receipt.canonical_payload())
+    return receipt
+
+
+def attempt_is_waiting_for_replay(attempt_dir: Path) -> bool:
+    """A request was sent and the replay gate has not reached a terminal result."""
+
+    if not (attempt_dir / "replay" / "request.json").exists():
+        return False
+    result = attempt_dir / "replay" / "replay.result.json"
+    if not result.exists():
+        return True
+    return GateResult.model_validate(read_json(result)).status == "unavailable"
+
+
+# --- Promotion ----------------------------------------------------------------
+
+
+@dataclass
+class PromotionPlan:
+    target: Optional[QualificationReceipt]
+    ready_branch: Optional[str]
+    close_branches: list[str] = field(default_factory=list)
+    reason: str = ""
+
+
+def plan_promotion(
+    receipts: Iterable[QualificationReceipt],
+    bundle: Mapping[str, Any],
+    open_candidate_branches: Iterable[str],
+) -> PromotionPlan:
+    """What to do with candidate PRs given the ledger and ``main``'s certificate."""
+
+    receipts = list(receipts)
+    current = certified_order_key(bundle)
+    target = select_promotion_target(receipts, current)
+    branch_pairs = {}
+    for receipt in receipts:
+        branch_pairs[candidate_branch(receipt.pair)] = receipt.pair.order_key
+    close = []
+    for branch in open_candidate_branches:
+        key = branch_pairs.get(branch)
+        if key is None:
+            continue
+        if key == current or dominates(current, key):
+            close.append(branch)
+        elif target is not None and dominates(target.pair.order_key, key):
+            close.append(branch)
+    if target is None:
+        return PromotionPlan(
+            target=None,
+            ready_branch=None,
+            close_branches=sorted(close),
+            reason=f"no promotable pair advances {current}",
+        )
+    return PromotionPlan(
+        target=target,
+        ready_branch=candidate_branch(target.pair),
+        close_branches=sorted(close),
+        reason=f"{target.pair.order_key} advances {current}",
+    )
+
+
+def candidate_pr_body(
+    receipt: Optional[QualificationReceipt],
+    pair: CandidatePair,
+    *,
+    ledger_url: str,
+    prepared: Optional[Mapping[str, Any]] = None,
+) -> str:
+    """Markdown body for a candidate PR: the pair, the gates and the verdict."""
+
+    lines = [
+        f"Automated certification candidate for **policyengine-uk {pair.model.version}**, "
+        f"**policyengine-core {pair.core.version}** and **uk-data {pair.data.release_version}** "
+        f"(`{pair.data.dataset}`, sha256 `{pair.data.dataset_sha256[:16]}…`).",
+        "",
+        f"- Pair id: `{pair.pair_id}`",
+        f"- Ledger: {ledger_url}",
+    ]
+    if prepared:
+        lines.append(f"- Compatibility basis: `{prepared.get('compatibility_basis')}`")
+    lines += ["", "| Gate | Status | Summary |", "|---|---|---|"]
+    gates = {gate.gate_id: gate for gate in (receipt.gates if receipt else [])}
+    for gate_id in REQUIRED_GATES:
+        gate = gates.get(gate_id)
+        if gate is None:
+            lines.append(f"| `{gate_id}` | pending | |")
+        else:
+            summary = gate.summary.replace("|", "\\|").replace("\n", " ")
+            lines.append(f"| `{gate_id}` | {gate.status} | {summary} |")
+    verdict = receipt.verdict if receipt else "pending"
+    lines += [
+        "",
+        f"**Verdict: {verdict}.** Merging this PR promotes the pair. Until cos d1344 "
+        "is ruled, promotion is a reviewed merge; the certification evidence test "
+        "refuses an exact-pair certificate without a promotable ledger receipt.",
+        "",
+        "🤖 Generated with [Claude Code](https://claude.com/claude-code)",
+    ]
+    return "\n".join(lines) + "\n"
+
+
+# --- Release dispatch to consumers ----------------------------------------------
+
+
+def release_bundle_identity(
+    bundle: Mapping[str, Any], country_id: str = "uk"
+) -> dict[str, Any]:
+    """The certified pair a release carries, as consumers verify it."""
+
+    record = bundle["data_releases"][country_id]
+    certification = record.get("certification") or {}
+    model_package = bundle["countries"][country_id]["model_package"]
+    return {
+        "model_version": record["model_package"]["version"],
+        "model_wheel_sha256": record["model_package"].get("sha256"),
+        "core_version": bundle["packages"][CORE_PACKAGE]["version"],
+        "data_release_version": record["data_package"]["version"],
+        "dataset": record["default_dataset"],
+        "dataset_sha256": record["certified_data_artifact"].get("sha256"),
+        "certificate_sha256": certificate_sha256(record),
+        "compatibility_basis": certification.get("compatibility_basis"),
+        "model_package": model_package,
+    }
+
+
+def release_dispatch_payload(
+    bundle: Mapping[str, Any],
+    *,
+    version: str,
+    repository: str = "PolicyEngine/policyengine.py",
+    fetch_receipt: Optional[
+        Callable[[str, str], Optional[QualificationReceipt]]
+    ] = None,
+) -> dict[str, Any]:
+    """``policyengine-release`` repository dispatch for consumers.
+
+    ``client_payload.version`` stays the first field, as the existing
+    sim-api and api updaters read only it.
+    """
+
+    if bundle.get("policyengine_version") != version:
+        raise ValueError(
+            f"The bundle manifest is for {bundle.get('policyengine_version')}, not {version}."
+        )
+    identity = release_bundle_identity(bundle)
+    qualification = None
+    certification = bundle["data_releases"]["uk"].get("certification") or {}
+    pair_id = certification.get("qualification_pair_id")
+    if pair_id:
+        receipt = fetch_receipt("uk", pair_id) if fetch_receipt is not None else None
+        qualification = {
+            "uk": {
+                "pair_id": pair_id,
+                "verdict": receipt.verdict if receipt is not None else None,
+                "receipt_sha256": receipt.receipt_sha256
+                if receipt is not None
+                else None,
+            }
+        }
+    return {
+        "event_type": "policyengine-release",
+        "client_payload": {
+            "version": version,
+            "bundle": {"uk": identity},
+            "qualification": qualification,
+            "release_url": f"https://github.com/{repository}/releases/tag/{version}",
+        },
+    }
+
+
+def released_bundle_request(
+    bundle: Mapping[str, Any],
+    *,
+    version: str,
+    wheel_sha256: str,
+    packaged_manifest_sha256: str,
+    release_bundle: Mapping[str, Optional[str]],
+    hf_file: Callable[[str, str, str], bytes],
+    pypi_project: Callable[[str], Mapping[str, Any]],
+    requested_by: Mapping[str, Any],
+) -> ReplayQualificationRequest:
+    """``released_bundle`` replay request for a published policyengine release."""
+
+    record = bundle["data_releases"]["uk"]
+    data_package = record["data_package"]
+    manifest_bytes = hf_file(
+        data_package["repo_id"],
+        data_package["release_manifest_revision"],
+        data_package["release_manifest_path"],
+    )
+    manifest = DataReleaseManifest.model_validate_json(manifest_bytes)
+    dataset = record["default_dataset"]
+    artifact = manifest.artifacts[dataset]
+    reference = record["datasets"][dataset]
+    if reference.get("sha256") != artifact.sha256:
+        raise ValueError(
+            "The release manifest's dataset hash differs from the bundle's."
+        )
+    core_version = bundle["packages"][CORE_PACKAGE]["version"]
+    core_wheel = _wheel(
+        pypi_project(CORE_PACKAGE)["releases"][core_version], CORE_PACKAGE, core_version
+    )
+    return ReplayQualificationRequest.model_validate(
+        {
+            "schema": "policyengine.uk-replay-qualification-request/v1",
+            "kind": "released_bundle",
+            "attempt": 1,
+            "candidate": {
+                "policyengine": {
+                    "version": version,
+                    "source": {"pypi": {"wheel_sha256": wheel_sha256}},
+                    "packaged_bundle_manifest_sha256": packaged_manifest_sha256,
+                },
+                "policyengine_uk": {
+                    "version": record["model_package"]["version"],
+                    "wheel_sha256": record["model_package"]["sha256"],
+                },
+                "policyengine_core": {
+                    "version": core_version,
+                    "wheel_sha256": core_wheel.sha256,
+                },
+                "data": {
+                    "build_id": record["certified_data_artifact"].get("build_id")
+                    or record["build_id"],
+                    "dataset": dataset,
+                    "repo_id": reference.get("repo_id") or data_package["repo_id"],
+                    "repo_type": reference.get("repo_type")
+                    or data_package.get("repo_type", "model"),
+                    "revision": reference["revision"],
+                    "path": reference["path"],
+                    "sha256": reference["sha256"],
+                    "size_bytes": artifact.size_bytes,
+                    "release_manifest_sha256": hashlib.sha256(
+                        manifest_bytes
+                    ).hexdigest(),
+                },
+                "expected_release_bundle": dict(release_bundle),
+            },
+            "compare_to": "latest_certified",
+            "requested_by": dict(requested_by),
+        }
+    )
diff --git a/tests/qualification_fixtures.py b/tests/qualification_fixtures.py
new file mode 100644
index 00000000..5f27153b
--- /dev/null
+++ b/tests/qualification_fixtures.py
@@ -0,0 +1,102 @@
+"""Shared builders for qualification tests (no network, no credentials)."""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+from policyengine.provenance.qualification import (
+    REQUIRED_GATES,
+    CandidatePair,
+    GateResult,
+    IssuedBy,
+    PinnedData,
+    PinnedWheel,
+    QualificationHarness,
+    QualificationReceipt,
+    qualification_verdict,
+)
+
+FIXTURES = Path(__file__).parent / "fixtures" / "uk_replay"
+VENDORED_SCHEMAS = (
+    Path(__file__).resolve().parents[1]
+    / "src"
+    / "policyengine"
+    / "data"
+    / "schemas"
+    / "vendor"
+    / "policyengine-scorecard"
+)
+
+
+def sha(char: str) -> str:
+    return char * 64
+
+
+def make_pair(
+    model="2.126.8", data="1.58.0", core="3.33.0", dataset_sha=None
+) -> CandidatePair:
+    return CandidatePair(
+        country_id="uk",
+        model=PinnedWheel(name="policyengine-uk", version=model, wheel_sha256=sha("a")),
+        core=PinnedWheel(name="policyengine-core", version=core, wheel_sha256=sha("b")),
+        data=PinnedData(
+            data_package="policyengine-uk-data",
+            release_version=data,
+            build_id=f"policyengine-uk-data-{data}",
+            repo_id="policyengine/policyengine-uk-data-private",
+            repo_type="model",
+            release_manifest_path=f"releases/{data}/release_manifest.json",
+            release_manifest_revision="f" * 40,
+            release_manifest_sha256=sha("c"),
+            dataset="enhanced_frs_2024_25",
+            dataset_path="enhanced_frs_2024_25.h5",
+            dataset_revision=data,
+            dataset_sha256=dataset_sha or sha("d"),
+            size_bytes=128369110,
+        ),
+    )
+
+
+HARNESS = QualificationHarness(
+    policyengine_version="6.2.6",
+    git_commit="e" * 40,
+    packaged_bundle_manifest_sha256=sha("9"),
+)
+ISSUED = IssuedBy(
+    repository="PolicyEngine/policyengine.py",
+    workflow_run_id=1,
+    run_url="https://github.com/PolicyEngine/policyengine.py/actions/runs/1",
+)
+
+
+def gates(status="pass", **overrides) -> list[GateResult]:
+    return [
+        GateResult(
+            gate_id=gate_id, status=overrides.get(gate_id, status), summary=gate_id
+        )
+        for gate_id in REQUIRED_GATES
+    ]
+
+
+def make_receipt(
+    pair=None, gate_results=None, completed_at="2026-10-15T09:00:00Z", review=None
+) -> QualificationReceipt:
+    pair = pair or make_pair()
+    gate_results = gate_results if gate_results is not None else gates()
+    return QualificationReceipt(
+        schema_version=1,
+        receipt_type="policyengine.candidate_qualification_receipt",
+        pair_id=pair.pair_id,
+        pair=pair,
+        harness=HARNESS,
+        gates=gate_results,
+        verdict=qualification_verdict(gate_results),
+        review=review,
+        issued_by=ISSUED,
+        completed_at=completed_at,
+    )
+
+
+def golden(name: str) -> dict:
+    return json.loads((FIXTURES / f"{name}.json").read_text(encoding="utf-8"))
diff --git a/tests/test_qualification_contracts.py b/tests/test_qualification_contracts.py
new file mode 100644
index 00000000..599cccdf
--- /dev/null
+++ b/tests/test_qualification_contracts.py
@@ -0,0 +1,446 @@
+"""Candidate qualification contracts, promotion order and the replay interface.
+
+Invariants:
+
+- the verdict is a pure, monotone function of the gate results: making any
+  gate worse never makes the verdict better, and a missing gate is never
+  qualified;
+- a review acceptance is bound to the exact receipt it accepts;
+- promotion picks the newest promotable pair that strictly advances the
+  certified pair, whatever order receipts arrive in, and never moves
+  backwards;
+- the replay request, status and receipt mirrors agree with the scorecard's
+  vendored JSON Schemas and reproduce its golden digests (differential);
+- a replay receipt counts only when bound to this request and these
+  artifacts; blocking flags fail, review flags need review.
+"""
+
+from __future__ import annotations
+
+import copy
+import json
+
+import jsonschema
+import pytest
+from hypothesis import given, settings
+from hypothesis import strategies as st
+from pydantic import ValidationError
+
+from policyengine.provenance.canonical import canonical_sha256
+from policyengine.provenance.qualification import (
+    REQUIRED_GATES,
+    GateResult,
+    ReplayQualificationRequest,
+    ReplayReceipt,
+    ReplayStatus,
+    ReviewAcceptance,
+    dominates,
+    evaluate_replay_receipt,
+    qualification_verdict,
+    select_promotion_target,
+)
+from tests.qualification_fixtures import (
+    FIXTURES,
+    VENDORED_SCHEMAS,
+    gates,
+    golden,
+    make_pair,
+    make_receipt,
+    sha,
+)
+
+STATUSES = ["pass", "needs_review", "unavailable", "fail", "error"]
+SEVERITY = {"pass": 0, "needs_review": 1, "unavailable": 2, "fail": 3, "error": 3}
+VERDICT_RANK = {"qualified": 0, "needs_review": 1, "incomplete": 2, "rejected": 3}
+
+
+# --- Verdict ------------------------------------------------------------------
+
+
+@pytest.mark.parametrize(
+    ("overrides", "verdict"),
+    [
+        ({}, "qualified"),
+        ({"replay": "needs_review"}, "needs_review"),
+        ({"reform_contract": "unavailable"}, "incomplete"),
+        ({"metrics_review": "unavailable", "replay": "needs_review"}, "incomplete"),
+        ({"wheel_hashes": "fail", "replay": "unavailable"}, "rejected"),
+        ({"budget_inputs": "error"}, "rejected"),
+    ],
+)
+def test_verdict_examples(overrides, verdict):
+    assert qualification_verdict(gates(**overrides)) == verdict
+
+
+def test_a_missing_required_gate_is_never_qualified():
+    for gate_id in REQUIRED_GATES:
+        partial = [gate for gate in gates() if gate.gate_id != gate_id]
+        assert qualification_verdict(partial) == "incomplete"
+
+
+@settings(max_examples=300, deadline=None)
+@given(
+    statuses=st.lists(
+        st.sampled_from(STATUSES),
+        min_size=len(REQUIRED_GATES),
+        max_size=len(REQUIRED_GATES),
+    ),
+    index=st.integers(0, len(REQUIRED_GATES) - 1),
+    worse=st.sampled_from(STATUSES),
+)
+def test_worsening_a_gate_never_improves_the_verdict(statuses, index, worse):
+    before = [
+        GateResult(gate_id=gate_id, status=status, summary="x")
+        for gate_id, status in zip(REQUIRED_GATES, statuses)
+    ]
+    if SEVERITY[worse] < SEVERITY[statuses[index]]:
+        return
+    after = list(before)
+    after[index] = GateResult(gate_id=REQUIRED_GATES[index], status=worse, summary="x")
+    assert (
+        VERDICT_RANK[qualification_verdict(after)]
+        >= VERDICT_RANK[qualification_verdict(before)]
+    )
+
+
+def test_receipt_verdict_must_follow_from_gates():
+    receipt = make_receipt(gate_results=gates(replay="needs_review"))
+    payload = receipt.model_dump(mode="json")
+    payload["verdict"] = "qualified"
+    with pytest.raises(ValidationError):
+        type(receipt).model_validate(payload)
+
+
+def test_pair_id_must_be_the_pair_digest():
+    payload = make_receipt().model_dump(mode="json")
+    payload["pair_id"] = sha("0")
+    with pytest.raises(ValidationError):
+        type(make_receipt()).model_validate(payload)
+
+
+# --- Review acceptance -----------------------------------------------------------
+
+
+def _accepted(receipt, digest=None):
+    return receipt.model_copy(
+        update={
+            "review": ReviewAcceptance(
+                reviewer="vahid",
+                accepted_at="2026-10-16T10:00:00Z",
+                accepted_receipt_sha256=digest or receipt.unreviewed_sha256,
+                explanation="UC moves follow the documented #2242 uplift.",
+            )
+        }
+    )
+
+
+def test_only_the_accepted_receipt_is_promotable():
+    receipt = make_receipt(gate_results=gates(replay="needs_review"))
+    assert not receipt.promotable
+    assert _accepted(receipt).promotable
+    assert not _accepted(receipt, digest=sha("1")).promotable
+    changed = receipt.model_copy(update={"completed_at": "2026-10-17T00:00:00Z"})
+    stale_acceptance = _accepted(changed, digest=receipt.unreviewed_sha256)
+    assert not stale_acceptance.promotable
+
+
+def test_review_cannot_attach_to_a_rejected_receipt():
+    receipt = make_receipt(gate_results=gates(wheel_hashes="fail"))
+    with pytest.raises(ValidationError):
+        type(receipt).model_validate(
+            {
+                **receipt.model_dump(mode="json"),
+                "review": _accepted(
+                    make_receipt(gate_results=gates(replay="needs_review"))
+                ).review.model_dump(),
+            }
+        )
+
+
+# --- Promotion order --------------------------------------------------------------
+
+VERSIONS = st.tuples(
+    st.sampled_from(["2.125.1", "2.126.6", "2.126.8", "2.127.0"]),
+    st.sampled_from(["1.58.0", "1.59.0", "1.60.0"]),
+    st.sampled_from(["3.33.0", "3.33.1"]),
+)
+
+
+@settings(max_examples=200, deadline=None)
+@given(a=VERSIONS, b=VERSIONS, c=VERSIONS)
+def test_dominance_is_a_strict_partial_order(a, b, c):
+    assert not dominates(a, a)
+    assert not (dominates(a, b) and dominates(b, a))
+    if dominates(a, b) and dominates(b, c):
+        assert dominates(a, c)
+
+
+RECEIPT_SPECS = st.lists(
+    st.tuples(
+        VERSIONS, st.sampled_from(["pass", "needs_review", "fail", "unavailable"])
+    ),
+    min_size=0,
+    max_size=6,
+)
+
+
+def _receipts(specs):
+    receipts = []
+    for index, ((model, data, core), status) in enumerate(specs):
+        receipts.append(
+            make_receipt(
+                pair=make_pair(model=model, data=data, core=core),
+                gate_results=gates(replay=status),
+                completed_at=f"2026-10-15T09:00:{index:02d}Z",
+            )
+        )
+    return receipts
+
+
+@settings(max_examples=200, deadline=None)
+@given(specs=RECEIPT_SPECS, current=VERSIONS, data=st.data())
+def test_promotion_target_is_order_independent_and_never_backwards(
+    specs, current, data
+):
+    receipts = _receipts(specs)
+    shuffled = data.draw(st.permutations(receipts))
+    target = select_promotion_target(receipts, current)
+    assert select_promotion_target(shuffled, current) == target
+    if target is None:
+        return
+    assert target.promotable
+    assert dominates(target.pair.order_key, current)
+    for other in receipts:
+        if other.promotable and dominates(other.pair.order_key, current):
+            key = other.pair.order_key
+            assert key == target.pair.order_key or dominates(target.pair.order_key, key)
+
+
+def test_a_stale_completion_cannot_displace_a_newer_accepted_candidate():
+    newer = make_receipt(
+        pair=make_pair(model="2.126.8"), completed_at="2026-10-15T09:00:00Z"
+    )
+    stale = make_receipt(
+        pair=make_pair(model="2.126.6"), completed_at="2026-10-15T12:00:00Z"
+    )
+    current = ("2.125.1", "1.58.0", "3.33.0")
+    assert select_promotion_target([newer, stale], current) == newer
+    assert select_promotion_target([stale, newer], current) == newer
+
+
+def test_incomparable_newest_pairs_promote_nothing_automatically():
+    newer_model = make_receipt(pair=make_pair(model="2.127.0", data="1.58.0"))
+    newer_data = make_receipt(pair=make_pair(model="2.126.8", data="1.59.0"))
+    assert (
+        select_promotion_target(
+            [newer_model, newer_data], ("2.125.1", "1.58.0", "3.33.0")
+        )
+        is None
+    )
+
+
+# --- Replay interface: mirrors agree with the vendored schemas ---------------
+
+
+def _validator(name):
+    schema = json.loads((VENDORED_SCHEMAS / name).read_text())
+    return jsonschema.Draft202012Validator(
+        schema, format_checker=jsonschema.Draft202012Validator.FORMAT_CHECKER
+    )
+
+
+def test_golden_request_round_trips_with_its_digest():
+    raw = golden("qualification_request_golden")
+    request = ReplayQualificationRequest.model_validate(raw)
+    assert request.document() == raw
+    digests = json.loads((FIXTURES / "DIGESTS.json").read_text())
+    assert request.request_id == canonical_sha256(raw)
+    assert (
+        request.request_id == digests["qualification_request_golden.json"]["request_id"]
+    )
+    _validator("qualification_request.v1.json").validate(request.document())
+
+
+def test_golden_receipt_digest_matches_received_bytes():
+    raw = golden("replay_receipt_golden")
+    receipt = ReplayReceipt.from_document(raw)
+    assert receipt.computed_receipt_sha256 == raw["receipt_sha256"]
+    _validator("replay_receipt.v1.json").validate(raw)
+
+
+REQUEST_MUTATIONS = [
+    ("extra member", lambda r: r.update(unexpected=True)),
+    ("bad kind", lambda r: r.update(kind="other")),
+    ("attempt zero", lambda r: r.update(attempt=0)),
+    ("bad dataset digest", lambda r: r["candidate"]["data"].update(sha256="xyz")),
+    ("bad repo type", lambda r: r["candidate"]["data"].update(repo_type="space")),
+    (
+        "wrapper with both sources",
+        lambda r: r["candidate"]["policyengine"]["source"].update(
+            pypi={"wheel_sha256": "a" * 64}
+        ),
+    ),
+    ("released bundle from git", lambda r: r.update(kind="released_bundle")),
+    (
+        "missing bundle field",
+        lambda r: r["candidate"]["expected_release_bundle"].pop("model_version"),
+    ),
+    ("bad commit", lambda r: r["requested_by"].update(commit="abc")),
+]
+
+
+@pytest.mark.parametrize(
+    ("label", "mutate"), REQUEST_MUTATIONS, ids=[m[0] for m in REQUEST_MUTATIONS]
+)
+def test_request_mirror_and_schema_reject_the_same_requests(label, mutate):
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    mutate(raw)
+    assert not _validator("qualification_request.v1.json").is_valid(raw), label
+    with pytest.raises(ValidationError):
+        ReplayQualificationRequest.model_validate(raw)
+
+
+def test_requested_by_is_open_as_in_the_schema():
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["requested_by"]["pair_id"] = sha("a")
+    request = ReplayQualificationRequest.model_validate(raw)
+    assert request.document()["requested_by"]["pair_id"] == sha("a")
+    _validator("qualification_request.v1.json").validate(request.document())
+
+
+# --- Replay gate ------------------------------------------------------------------
+
+
+def _sealed(receipt_doc):
+    doc = {key: value for key, value in receipt_doc.items() if key != "receipt_sha256"}
+    doc["receipt_sha256"] = canonical_sha256(doc)
+    return doc
+
+
+def _status(request_id, receipt_doc, status=None):
+    return ReplayStatus.model_validate(
+        {
+            "schema": "policyengine.uk-replay-status/v1",
+            "request_id": request_id,
+            "status": status or receipt_doc["status"],
+            "history": [
+                {
+                    "status": status or receipt_doc["status"],
+                    "at": "2026-10-15T10:00:00Z",
+                    "run_url": "https://github.com/PolicyEngine/policyengine-scorecard/actions/runs/7",
+                }
+            ],
+            "receipt_sha256": receipt_doc["receipt_sha256"],
+            "receipt_commit": "c" * 40,
+        }
+    )
+
+
+def _gate(receipt_doc, request=None, status=None):
+    request = request or ReplayQualificationRequest.model_validate(
+        golden("qualification_request_golden")
+    )
+    receipt = ReplayReceipt.from_document(receipt_doc)
+    return evaluate_replay_receipt(
+        request, status or _status(request.request_id, receipt_doc), receipt
+    )
+
+
+def _with_counts(**counts):
+    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    base = {key: 0 for key in doc["diff"]["flag_counts"]}
+    base.update(counts)
+    doc["diff"]["flag_counts"] = base
+    return _sealed(doc)
+
+
+def test_golden_receipt_fails_on_its_structural_flag():
+    gate = _gate(golden("replay_receipt_golden"))
+    assert gate.status == "fail"
+    assert "structural" in gate.summary
+
+
+@pytest.mark.parametrize(
+    ("counts", "status"),
+    [
+        ({}, "pass"),
+        ({"numerical": 2}, "needs_review"),
+        ({"support": 1}, "needs_review"),
+        ({"numerical": 2, "coverage": 1}, "fail"),
+        ({"construction": 1}, "fail"),
+        ({"inertness": 1}, "fail"),
+        ({"mapping": 3}, "fail"),
+    ],
+)
+def test_flag_policy(counts, status):
+    assert _gate(_with_counts(**counts)).status == status
+
+
+def test_incomplete_or_failed_integrity_fails():
+    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    doc["diff"]["flag_counts"] = {key: 0 for key in doc["diff"]["flag_counts"]}
+    doc["integrity"]["status"] = "incomplete"
+    assert _gate(_sealed(doc)).status == "fail"
+    doc["integrity"] = {
+        "status": "failed",
+        "failures": [{"code": "non_finite", "detail": "NaN in VAT"}],
+    }
+    doc["status"] = "failed"
+    assert _gate(_sealed(doc)).status == "fail"
+
+
+def test_execution_of_other_artifacts_fails():
+    for mutate in (
+        lambda d: d["execution"].update(dataset_sha256="0" * 64),
+        lambda d: d["execution"].update(packaged_bundle_manifest_sha256="0" * 64),
+        lambda d: d["execution"]["packages"]["policyengine-uk"].update(version="9.9.9"),
+        lambda d: d["execution"]["release_bundle"].update(model_version="9.9.9"),
+    ):
+        doc = copy.deepcopy(_with_counts())
+        mutate(doc)
+        assert _gate(_sealed(doc)).status == "fail"
+
+
+def test_unbound_receipts_fail():
+    sealed = _with_counts()
+    tampered = copy.deepcopy(sealed)
+    tampered["diff"]["flag_counts"]["numerical"] = 0
+    tampered["corpus"]["corpus_version"] = "tampered"
+    assert _gate(tampered).status == "fail"  # digest no longer matches the bytes
+    request = ReplayQualificationRequest.model_validate(
+        golden("qualification_request_golden")
+    )
+    other = _status("0" * 64, sealed)
+    assert _gate(sealed, request=request, status=other).status == "fail"
+
+
+def test_rejected_receipt_fails_with_its_code():
+    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    doc.update(
+        status="rejected",
+        rejection={"code": "artifact_hash_mismatch", "detail": "dataset bytes differ"},
+        corpus=None,
+        diff=None,
+    )
+    doc["integrity"] = {"status": "not_run", "failures": []}
+    gate = _gate(_sealed(doc))
+    assert gate.status == "fail"
+    assert "artifact_hash_mismatch" in gate.summary
+
+
+def test_status_must_name_terminal_receipt():
+    with pytest.raises(ValidationError):
+        ReplayStatus.model_validate(
+            {
+                "schema": "policyengine.uk-replay-status/v1",
+                "request_id": "a" * 64,
+                "status": "complete",
+                "history": [
+                    {
+                        "status": "complete",
+                        "at": "2026-10-15T10:00:00Z",
+                        "run_url": "https://github.com/PolicyEngine/policyengine-scorecard/actions/runs/7",
+                    }
+                ],
+            }
+        )
diff --git a/tests/test_qualified_pair_certification.py b/tests/test_qualified_pair_certification.py
new file mode 100644
index 00000000..85028763
--- /dev/null
+++ b/tests/test_qualified_pair_certification.py
@@ -0,0 +1,387 @@
+"""Certification on an automated qualification of the exact pair.
+
+Invariants:
+
+- ``qualified_exact_pair`` is used only when neither the build-time model
+  nor a publisher claim covers the model; it is exact (one model version,
+  one core version, one data build) and names the qualified pair;
+- the core must be the build core, publisher-claimed, or qualified;
+- at runtime a qualified certificate is honoured only for exactly its model
+  version and data build, online and offline;
+- a bundle certificate on that basis needs a promotable ledger receipt for
+  exactly what it certifies (``verify_certification_evidence``).
+"""
+
+from __future__ import annotations
+
+import copy
+import json
+from pathlib import Path
+from unittest.mock import MagicMock, patch
+
+import pytest
+from hypothesis import given, settings
+from hypothesis import strategies as st
+
+from policyengine.provenance.certification import (
+    BASIS_QUALIFIED_PAIR,
+    CertificationError,
+    build_country_manifest_payload,
+    validate_release_manifest,
+)
+from policyengine.provenance.manifest import (
+    DataCertification,
+    DataReleaseManifest,
+    DataReleaseManifestUnavailableError,
+    certify_data_release_compatibility,
+    get_data_release_manifest,
+)
+from policyengine.provenance.qualification_ledger import (
+    latest_receipts,
+    pending_attempts,
+    verify_certification_evidence,
+    write_json,
+)
+from tests.qualification_fixtures import gates, make_pair, make_receipt
+
+PAIR_ID = "a" * 64
+
+
+def _uk_manifest(
+    model_claims=("==2.122.2",), core_claims=("==3.32.13",)
+) -> DataReleaseManifest:
+    return DataReleaseManifest.model_validate(
+        {
+            "schema_version": 1,
+            "data_package": {"name": "policyengine-uk-data", "version": "1.58.0"},
+            "compatible_model_packages": [
+                {"name": "policyengine-uk", "specifier": spec} for spec in model_claims
+            ],
+            "compatible_core_packages": [
+                {"name": "policyengine-core", "specifier": spec} for spec in core_claims
+            ],
+            "default_datasets": {"national": "enhanced_frs_2024_25"},
+            "build": {
+                "build_id": "policyengine-uk-data-1.58.0",
+                "built_with_core_package": {
+                    "name": "policyengine-core",
+                    "version": "3.32.13",
+                },
+                "built_with_model_package": {
+                    "name": "policyengine-uk",
+                    "version": "2.122.2",
+                    "data_build_fingerprint": "sha256:build",
+                },
+            },
+            "artifacts": {
+                "enhanced_frs_2024_25": {
+                    "kind": "microdata",
+                    "path": "enhanced_frs_2024_25.h5",
+                    "repo_id": "policyengine/policyengine-uk-data-private",
+                    "revision": "1.58.0",
+                    "sha256": "d" * 64,
+                    "size_bytes": 10,
+                }
+            },
+        }
+    )
+
+
+class TestValidateWithQualification:
+    def test_uncovered_model_is_admitted_only_with_a_pair_id(self):
+        with pytest.raises(CertificationError, match="qualification"):
+            validate_release_manifest(_uk_manifest(), "policyengine-uk", "2.126.8")
+        basis, warnings = validate_release_manifest(
+            _uk_manifest(core_claims=("==3.33.0",)),
+            "policyengine-uk",
+            "2.126.8",
+            core_version="3.33.0",
+            qualified_pair_id=PAIR_ID,
+        )
+        assert basis == BASIS_QUALIFIED_PAIR
+        assert any("exactly policyengine-uk==2.126.8" in item for item in warnings)
+
+    def test_stronger_bases_win_over_qualification(self):
+        basis, _ = validate_release_manifest(
+            _uk_manifest(), "policyengine-uk", "2.122.2", qualified_pair_id=PAIR_ID
+        )
+        assert basis == "built_with_model_package"
+        basis, _ = validate_release_manifest(
+            _uk_manifest(model_claims=("==2.122.2", "==2.126.8")),
+            "policyengine-uk",
+            "2.126.8",
+            qualified_pair_id=PAIR_ID,
+        )
+        assert basis == "legacy_compatible_model_package"
+
+    def test_qualified_pair_needs_its_core_version(self):
+        with pytest.raises(CertificationError, match="core"):
+            validate_release_manifest(
+                _uk_manifest(), "policyengine-uk", "2.126.8", qualified_pair_id=PAIR_ID
+            )
+
+    def test_core_outside_claims_is_refused_unless_qualified(self):
+        with pytest.raises(CertificationError, match="policyengine-core 3.34.0"):
+            validate_release_manifest(
+                _uk_manifest(model_claims=("==2.126.8",)),
+                "policyengine-uk",
+                "2.126.8",
+                core_version="3.34.0",
+            )
+        basis, warnings = validate_release_manifest(
+            _uk_manifest(),
+            "policyengine-uk",
+            "2.126.8",
+            core_version="3.34.0",
+            qualified_pair_id=PAIR_ID,
+        )
+        assert basis == BASIS_QUALIFIED_PAIR
+        assert any("outside the publisher's core claims" in item for item in warnings)
+
+    def test_build_core_and_claimed_core_pass(self):
+        for core in ("3.32.13",):
+            validate_release_manifest(
+                _uk_manifest(), "policyengine-uk", "2.122.2", core_version=core
+            )
+
+    def test_payload_names_the_pair_and_core(self):
+        manifest = _uk_manifest()
+        payload = build_country_manifest_payload(
+            country="uk",
+            manifest=manifest,
+            uri_parts={
+                "repo_type": "model",
+                "repo_id": "policyengine/policyengine-uk-data-private",
+                "revision": "f" * 40,
+                "path": "releases/1.58.0/release_manifest.json",
+            },
+            policyengine_version="6.2.7",
+            model_package="policyengine-uk",
+            model_version="2.126.8",
+            model_wheel={
+                "sha256": "a" * 64,
+                "url": "https://files.pythonhosted.org/x.whl",
+            },
+            compatibility_basis=BASIS_QUALIFIED_PAIR,
+            core_version="3.33.0",
+            qualified_pair_id=PAIR_ID,
+        )
+        certification = payload["certification"]
+        assert certification["compatibility_basis"] == BASIS_QUALIFIED_PAIR
+        assert certification["certified_for_core_version"] == "3.33.0"
+        assert certification["qualification_pair_id"] == PAIR_ID
+        assert certification["qualification_ledger_url"].endswith(f"/uk/{PAIR_ID}")
+
+
+def _response(payload):
+    response = MagicMock()
+    response.status_code = 200
+    response.text = json.dumps(payload)
+    response.content = response.text.encode()
+    response.raise_for_status.return_value = None
+    return response
+
+
+def _qualified(model="2.126.8", build_id="policyengine-uk-data-1.58.0"):
+    return DataCertification(
+        compatibility_basis="qualified_exact_pair",
+        certified_for_model_version=model,
+        certified_for_core_version="3.33.0",
+        data_build_id=build_id,
+        data_build_fingerprint="sha256:build",
+        qualification_pair_id=PAIR_ID,
+    )
+
+
+class TestRuntimeAcceptance:
+    def setup_method(self):
+        get_data_release_manifest.cache_clear()
+
+    def _certify(self, bundled, runtime_model, remote=None, fingerprint=None):
+        manifest = MagicMock(certification=bundled)
+        manifest.model_package.name = "policyengine-uk"
+        manifest.data_package = MagicMock(
+            release_manifest_revision=None, repo_id="r", version="1.58.0"
+        )
+        patches = [
+            patch(
+                "policyengine.provenance.manifest.get_release_manifest",
+                return_value=manifest,
+            )
+        ]
+        if remote is None:
+            patches.append(
+                patch(
+                    "policyengine.provenance.manifest.get_data_release_manifest",
+                    side_effect=DataReleaseManifestUnavailableError("private"),
+                )
+            )
+        else:
+            patches.append(
+                patch(
+                    "policyengine.provenance.manifest.get_data_release_manifest",
+                    return_value=remote,
+                )
+            )
+        with patches[0], patches[1]:
+            return certify_data_release_compatibility(
+                "uk",
+                runtime_model_version=runtime_model,
+                runtime_data_build_fingerprint=fingerprint,
+            )
+
+    def test_online_exact_model_and_build_is_honoured(self):
+        certification = self._certify(_qualified(), "2.126.8", remote=_uk_manifest())
+        assert certification.compatibility_basis == "qualified_exact_pair"
+
+    def test_online_other_model_version_is_refused(self):
+        with pytest.raises(ValueError, match="not certified"):
+            self._certify(_qualified(), "2.126.9", remote=_uk_manifest())
+
+    def test_online_other_data_build_is_refused(self):
+        with pytest.raises(ValueError, match="not certified"):
+            self._certify(
+                _qualified(build_id="policyengine-uk-data-1.59.0"),
+                "2.126.8",
+                remote=_uk_manifest(),
+            )
+
+    def test_offline_fingerprint_difference_is_expected(self):
+        certification = self._certify(
+            _qualified(), "2.126.8", fingerprint="sha256:runtime"
+        )
+        assert certification.compatibility_basis == "qualified_exact_pair"
+
+
+# --- Ledger evidence ---------------------------------------------------------
+
+
+def _record_for(receipt):
+    pair = receipt.pair
+    return {
+        "certification": {
+            "compatibility_basis": "qualified_exact_pair",
+            "qualification_pair_id": pair.pair_id,
+            "certified_for_model_version": pair.model.version,
+            "certified_for_core_version": pair.core.version,
+            "data_build_id": pair.data.build_id,
+        },
+        "model_package": {
+            "version": pair.model.version,
+            "sha256": pair.model.wheel_sha256,
+        },
+        "data_package": {
+            "version": pair.data.release_version,
+            "release_manifest_revision": pair.data.release_manifest_revision,
+        },
+        "default_dataset": pair.data.dataset,
+        "certified_data_artifact": {"sha256": pair.data.dataset_sha256},
+    }
+
+
+def test_other_bases_need_no_ledger_evidence():
+    assert (
+        verify_certification_evidence(
+            {
+                "certification": {
+                    "compatibility_basis": "legacy_compatible_model_package"
+                }
+            },
+            None,
+        )
+        == []
+    )
+
+
+def test_matching_promotable_receipt_is_sufficient():
+    receipt = make_receipt()
+    assert verify_certification_evidence(_record_for(receipt), receipt) == []
+
+
+def test_missing_or_unpromotable_receipt_is_refused():
+    receipt = make_receipt()
+    record = _record_for(receipt)
+    assert verify_certification_evidence(record, None)
+    pending = make_receipt(gate_results=gates(replay="needs_review"))
+    assert verify_certification_evidence(_record_for(pending), pending)
+
+
+FIELDS = [
+    ("certification", "certified_for_model_version"),
+    ("certification", "certified_for_core_version"),
+    ("certification", "data_build_id"),
+    ("model_package", "version"),
+    ("model_package", "sha256"),
+    ("data_package", "version"),
+    ("data_package", "release_manifest_revision"),
+    ("certified_data_artifact", "sha256"),
+]
+
+
+@settings(max_examples=60, deadline=None)
+@given(field=st.sampled_from(FIELDS), value=st.text(min_size=1, max_size=8))
+def test_any_certified_field_differing_from_the_receipt_is_refused(field, value):
+    receipt = make_receipt()
+    record = copy.deepcopy(_record_for(receipt))
+    if record[field[0]][field[1]] == value:
+        return
+    record[field[0]][field[1]] = value
+    assert verify_certification_evidence(record, receipt)
+
+
+def test_ledger_listing(tmp_path):
+    qualified = make_receipt()
+    write_json(
+        tmp_path / "uk" / qualified.pair_id / "qualification_receipt.json",
+        qualified.canonical_payload(),
+    )
+    pending = (
+        tmp_path / "uk" / ("b" * 64) / "attempts" / "abc" / "replay" / "request.json"
+    )
+    write_json(pending, {"schema": "x"})
+    assert [r.pair_id for r in latest_receipts(tmp_path)] == [qualified.pair_id]
+    assert pending_attempts(tmp_path) == [pending.parent.parent]
+
+
+def test_committed_bundle_has_ledger_evidence_for_qualified_pairs():
+    """The release gate: an exact-pair certificate ships only with its evidence."""
+
+    from policyengine.provenance.qualification_ledger import fetch_ledger_receipt
+
+    bundle_path = (
+        Path(__file__).resolve().parents[1]
+        / "src"
+        / "policyengine"
+        / "data"
+        / "bundle"
+        / "manifest.json"
+    )
+    bundle = json.loads(bundle_path.read_text())
+    checked = 0
+    for country_id, record in bundle["data_releases"].items():
+        certification = record.get("certification") or {}
+        if certification.get("compatibility_basis") != "qualified_exact_pair":
+            continue
+        receipt = fetch_ledger_receipt(
+            country_id, certification["qualification_pair_id"]
+        )
+        assert verify_certification_evidence(record, receipt) == []
+        checked += 1
+    qualified = [
+        country_id
+        for country_id, record in bundle["data_releases"].items()
+        if (record.get("certification") or {}).get("compatibility_basis")
+        == "qualified_exact_pair"
+    ]
+    assert checked == len(qualified)
+
+
+def test_pair_id_changes_with_any_pinned_identity():
+    base = make_pair()
+    for variant in (
+        make_pair(model="2.126.9"),
+        make_pair(core="3.33.1"),
+        make_pair(data="1.59.0"),
+        make_pair(dataset_sha="0" * 64),
+    ):
+        assert variant.pair_id != base.pair_id
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
new file mode 100644
index 00000000..bca2a2ff
--- /dev/null
+++ b/tests/test_uk_candidate_gates.py
@@ -0,0 +1,994 @@
+"""Mandatory local qualification gates (no network, no credentials).
+
+Invariants:
+
+- installed files match the wheel byte for byte, or the gate fails: mutating
+  any single installed file fails it;
+- no gate can skip: a missing harness is ``unavailable`` and a crash is
+  ``error``; ``run_gates`` returns exactly one result per gate;
+- inputs newly missing from the data are exactly (missing now) − (missing
+  before); a critical input that becomes unusable always fails;
+- metric review is monotone: shrinking every move toward zero never makes
+  the status worse.
+"""
+
+from __future__ import annotations
+
+import base64
+import hashlib
+import io
+import zipfile
+from pathlib import Path
+from types import SimpleNamespace
+
+import pandas as pd
+import pytest
+from hypothesis import given, settings
+from hypothesis import strategies as st
+
+from policyengine.provenance import uk_candidate as gates_module
+from policyengine.provenance.manifest import DataReleaseManifest
+from policyengine.provenance.uk_candidate import (
+    budget_inputs,
+    compare_metric_reports,
+    core_compatibility,
+    data_access,
+    dataset_bytes,
+    installed_versions,
+    metrics_review,
+    parse_record,
+    record_digest_to_hex,
+    reform_contract,
+    run_gates,
+    supported_years,
+    verify_installed_against_wheel,
+    wheel_hashes,
+)
+from tests.qualification_fixtures import HARNESS, make_pair
+
+# --- Installed versions --------------------------------------------------------
+
+
+class FakeMetadata:
+    PackageNotFoundError = KeyError
+
+    def __init__(self, versions, requires):
+        self.versions, self._requires = versions, requires
+
+    def version(self, name):
+        return self.versions[name]
+
+    def requires(self, name):
+        return self._requires.get(name, [])
+
+
+def test_installed_versions_pass_and_fail():
+    pair = make_pair()
+    versions = {
+        "policyengine": "6.2.6",
+        "policyengine-uk": "2.126.8",
+        "policyengine-core": "3.33.0",
+        "numpy": "2.1.0",
+    }
+    requires = {
+        "policyengine-uk": ["policyengine-core>=3.32.27", "numpy>=1.26"],
+        "policyengine": ["pydantic; extra == 'docs'"],
+    }
+    result, _ = installed_versions(
+        pair, HARNESS, metadata=FakeMetadata(versions, requires)
+    )
+    assert result.status == "pass", result.summary
+    result, evidence = installed_versions(
+        pair,
+        HARNESS,
+        metadata=FakeMetadata({**versions, "policyengine-uk": "2.126.6"}, requires),
+    )
+    assert result.status == "fail" and "2.126.6" in result.summary
+    result, _ = installed_versions(
+        pair,
+        HARNESS,
+        metadata=FakeMetadata({**versions, "policyengine-core": "3.30.0"}, requires),
+    )
+    assert result.status == "fail"
+    result, _ = installed_versions(
+        pair,
+        HARNESS,
+        metadata=FakeMetadata(
+            versions, {**requires, "policyengine-core": ["missing-pkg>=1"]}
+        ),
+    )
+    assert result.status == "fail" and "missing-pkg" in result.summary
+
+
+# --- Wheel RECORD verification ----------------------------------------------------
+
+
+def _b64(data: bytes) -> str:
+    return base64.urlsafe_b64encode(hashlib.sha256(data).digest()).decode().rstrip("=")
+
+
+FILES = {
+    "policyengine_uk/__init__.py": b"VERSION = '2.126.8'\n",
+    "policyengine_uk/system.py": b"system = object()\n",
+    "policyengine_uk/parameters/rate.yaml": b"values:\n  2027-04-06: 0.2\n",
+}
+
+
+def _build(tmp_path: Path, files=FILES):
+    dist_info = "policyengine_uk-2.126.8.dist-info"
+    record_lines = [
+        f"{path},sha256={_b64(data)},{len(data)}" for path, data in files.items()
+    ]
+    record_lines.append(f"{dist_info}/RECORD,,")
+    wheel = tmp_path / "policyengine_uk-2.126.8-py3-none-any.whl"
+    with zipfile.ZipFile(wheel, "w") as archive:
+        for path, data in files.items():
+            archive.writestr(path, data)
+        archive.writestr(f"{dist_info}/RECORD", "\n".join(record_lines) + "\n")
+    site = tmp_path / "site"
+    for path, data in files.items():
+        (site / path).parent.mkdir(parents=True, exist_ok=True)
+        (site / path).write_bytes(data)
+    installed_record = record_lines + [
+        f"{dist_info}/INSTALLER,sha256={_b64(b'uv')},2",
+        f"{dist_info}/REQUESTED,,",
+    ]
+    return wheel, site, installed_record
+
+
+class FakeDistribution:
+    def __init__(self, site: Path, record_lines):
+        self.site = site
+        self.files = []
+        for line in record_lines:
+            path, digest, *_ = line.split(",")
+            hash_ = (
+                SimpleNamespace(mode="sha256", value=digest.split("=", 1)[1])
+                if digest
+                else None
+            )
+            self.files.append(SimpleNamespace(hash=hash_, __str__=None, path=path))
+
+    def locate_file(self, path):
+        return self.site / path
+
+
+class _File(str):
+    pass
+
+
+def _distribution(site, record_lines):
+    dist = SimpleNamespace(site=site, files=[], locate_file=lambda path: site / path)
+    for line in record_lines:
+        path, digest, *_ = line.split(",")
+        item = _File(path)
+        item.hash = (
+            SimpleNamespace(mode="sha256", value=digest.split("=", 1)[1])
+            if digest
+            else None
+        )
+        dist.files.append(item)
+    return dist
+
+
+def _metadata_for(site, record_lines):
+    return SimpleNamespace(distribution=lambda name: _distribution(site, record_lines))
+
+
+def test_record_hash_decoding():
+    data = b"hello"
+    assert (
+        record_digest_to_hex(f"sha256={_b64(data)}") == hashlib.sha256(data).hexdigest()
+    )
+    parsed = parse_record(f"a.py,sha256={_b64(data)},5\nRECORD,,\n")
+    assert parsed == {"a.py": hashlib.sha256(data).hexdigest(), "RECORD": None}
+    with pytest.raises(ValueError):
+        record_digest_to_hex("md5=abc")
+
+
+def test_untouched_install_verifies(tmp_path):
+    wheel, site, record = _build(tmp_path)
+    evidence = verify_installed_against_wheel(
+        "policyengine-uk", wheel, metadata=_metadata_for(site, record)
+    )
+    assert evidence["problems"] == []
+    assert evidence["files_verified"] == len(FILES)
+
+
+@settings(max_examples=30, deadline=None)
+@given(index=st.integers(0, len(FILES) - 1), extra=st.binary(min_size=1, max_size=8))
+def test_any_mutated_installed_file_fails(tmp_path_factory, index, extra):
+    tmp_path = tmp_path_factory.mktemp("wheel")
+    wheel, site, record = _build(tmp_path)
+    target = site / list(FILES)[index]
+    target.write_bytes(target.read_bytes() + extra)
+    evidence = verify_installed_against_wheel(
+        "policyengine-uk", wheel, metadata=_metadata_for(site, record)
+    )
+    assert evidence["problems"]
+
+
+def test_extra_installed_file_fails(tmp_path):
+    wheel, site, record = _build(tmp_path)
+    (site / "policyengine_uk" / "injected.py").write_bytes(b"x = 1\n")
+    record = record + [f"policyengine_uk/injected.py,sha256={_b64(b'x = 1')},6"]
+    evidence = verify_installed_against_wheel(
+        "policyengine-uk", wheel, metadata=_metadata_for(site, record)
+    )
+    assert any("injected.py" in problem for problem in evidence["problems"])
+
+
+def test_wheel_hash_gate(tmp_path):
+    wheel, site, record = _build(tmp_path)
+    digest = hashlib.sha256(wheel.read_bytes()).hexdigest()
+    pair = make_pair()
+    pair = pair.model_copy(
+        update={"model": pair.model.model_copy(update={"wheel_sha256": digest})}
+    )
+    (tmp_path / "core").mkdir()
+    core_wheel, core_site, core_record = _build(tmp_path / "core")
+    core_digest = hashlib.sha256(core_wheel.read_bytes()).hexdigest()
+    pair = pair.model_copy(
+        update={"core": pair.core.model_copy(update={"wheel_sha256": core_digest})}
+    )
+    metadata = SimpleNamespace(
+        distribution=lambda name: (
+            _distribution(site, record)
+            if name == "policyengine-uk"
+            else _distribution(core_site, core_record)
+        )
+    )
+    result, _ = wheel_hashes(
+        pair,
+        wheel_paths={"policyengine-uk": wheel, "policyengine-core": core_wheel},
+        pypi_digests={"policyengine-uk": digest, "policyengine-core": core_digest},
+        metadata=metadata,
+    )
+    assert result.status == "pass", result.summary
+    result, _ = wheel_hashes(
+        pair,
+        wheel_paths={"policyengine-uk": wheel, "policyengine-core": core_wheel},
+        pypi_digests={"policyengine-uk": "0" * 64, "policyengine-core": core_digest},
+        metadata=metadata,
+    )
+    assert result.status == "fail"
+
+
+# --- Core compatibility, data access, bytes, years -----------------------------------
+
+
+def _manifest(model_claims=(), core_claims=()):
+    return DataReleaseManifest.model_validate(
+        {
+            "schema_version": 1,
+            "data_package": {"name": "policyengine-uk-data", "version": "1.58.0"},
+            "compatible_model_packages": [
+                {"name": "policyengine-uk", "specifier": s} for s in model_claims
+            ],
+            "compatible_core_packages": [
+                {"name": "policyengine-core", "specifier": s} for s in core_claims
+            ],
+            "default_datasets": {"national": "enhanced_frs_2024_25"},
+            "build": {
+                "build_id": "b",
+                "built_with_model_package": {
+                    "name": "policyengine-uk",
+                    "version": "2.122.2",
+                },
+            },
+            "artifacts": {
+                "enhanced_frs_2024_25": {
+                    "kind": "microdata",
+                    "path": "enhanced_frs_2024_25.h5",
+                    "repo_id": "policyengine/policyengine-uk-data-private",
+                    "revision": "1.58.0",
+                    "sha256": "d" * 64,
+                },
+                "frs_2024_25": {
+                    "kind": "microdata",
+                    "path": "frs_2024_25.h5",
+                    "repo_id": "policyengine/policyengine-uk-data-private",
+                    "revision": "1.58.0",
+                },
+            },
+        }
+    )
+
+
+def test_core_compatibility():
+    pair = make_pair()
+    result, evidence = core_compatibility(
+        pair, _manifest(), model_requires_core=">=3.32.27"
+    )
+    assert result.status == "pass" and evidence["publisher_claim_covers_model"] is False
+    result, _ = core_compatibility(
+        pair, _manifest(["==2.126.8"], ["==3.33.0"]), model_requires_core=">=3.32.27"
+    )
+    assert result.details == {
+        "publisher_claim_covers_model": True,
+        "publisher_claim_covers_core": True,
+    }
+    result, _ = core_compatibility(pair, _manifest(), model_requires_core=">=3.34")
+    assert result.status == "fail"
+
+
+class _Response:
+    def __init__(self, status, content=b""):
+        self.status_code, self.content = status, content
+
+
+def test_data_access():
+    pair = make_pair()
+    manifest_bytes = _manifest().model_dump_json().encode()
+    pair = pair.model_copy(
+        update={
+            "data": pair.data.model_copy(
+                update={
+                    "release_manifest_sha256": hashlib.sha256(
+                        manifest_bytes
+                    ).hexdigest()
+                }
+            )
+        }
+    )
+
+    def get(url, headers=None, timeout=None):
+        return _Response(200 if headers else 401, manifest_bytes)
+
+    def head(url, headers=None, timeout=None, allow_redirects=True):
+        return _Response(200 if headers else 401)
+
+    result, evidence, manifest = data_access(pair, get=get, head=head, token="t")
+    assert result.status == "pass" and manifest is not None
+    assert evidence["anonymous_dataset_status"] == 401
+    result, _, _ = data_access(pair, get=get, head=head, token=None)
+    assert result.status == "fail"
+    result, _, _ = data_access(
+        pair, get=get, head=lambda *a, **k: _Response(200), token="t"
+    )
+    assert result.status == "fail" and "without credentials" in result.summary
+    result, _, _ = data_access(
+        pair,
+        get=get,
+        head=lambda url, headers=None, **k: _Response(
+            404
+            if headers and "frs_2024_25.h5" in url and "enhanced" not in url
+            else (200 if headers else 401)
+        ),
+        token="t",
+    )
+    assert result.status == "fail" and "frs_2024_25 returned HTTP 404" in result.summary
+
+
+def _tiny_dataset(path: Path, year=2024, extra_person=None):
+    person = pd.DataFrame(
+        {
+            "person_id": [1, 2],
+            "age": [30.0, 5.0],
+            "employment_income": [30000.0, 0.0],
+            **(extra_person or {}),
+        }
+    )
+    benunit = pd.DataFrame({"benunit_id": [1], "would_claim_uc": [True]})
+    household = pd.DataFrame(
+        {"household_id": [1], "household_weight": [100.0], "rent": [0.0]}
+    )
+    with pd.HDFStore(path, mode="w") as store:
+        store.put("person", person)
+        store.put("benunit", benunit)
+        store.put("household", household)
+        store.put("time_period", pd.Series([str(year)]))
+    return path
+
+
+def test_dataset_bytes(tmp_path):
+    path = _tiny_dataset(tmp_path / "data.h5")
+    digest = hashlib.sha256(path.read_bytes()).hexdigest()
+    pair = make_pair(dataset_sha=digest)
+    pair = pair.model_copy(
+        update={
+            "data": pair.data.model_copy(update={"size_bytes": path.stat().st_size})
+        }
+    )
+    assert dataset_bytes(pair, path)[0].status == "pass"
+    assert dataset_bytes(make_pair(), path)[0].status == "fail"
+
+
+@pytest.mark.parametrize(
+    ("projected", "previous", "status"),
+    [
+        (list(range(2024, 2032)), list(range(2024, 2031)), "pass"),
+        (list(range(2024, 2031)), list(range(2024, 2031)), "needs_review"),
+        (list(range(2024, 2030)), list(range(2024, 2031)), "fail"),
+        (list(range(2026, 2031)), None, "fail"),
+        ([2020, 2021], None, "fail"),
+    ],
+)
+def test_supported_years(tmp_path, projected, previous, status):
+    path = _tiny_dataset(tmp_path / "data.h5", year=max(projected[0], 2024))
+    result, evidence = supported_years(
+        make_pair(),
+        path,
+        required_years=list(range(2025, 2031)),
+        budget_horizon_years=list(range(2026, 2032)),
+        previous_supported_years=previous,
+        projected_years=lambda _: projected,
+    )
+    assert result.status == status, result.summary
+
+
+# --- Budget inputs -------------------------------------------------------------------
+
+INPUT_NAMES = [
+    "age",
+    "employment_income",
+    "rent",
+    "would_claim_uc",
+    "household_weight",
+    "new_input_a",
+    "new_input_b",
+]
+
+
+def _tables(columns):
+    tables = {
+        "person": pd.DataFrame({"age": [30.0, 5.0], "employment_income": [3.0e4, 0.0]})
+    }
+    tables["household"] = pd.DataFrame(
+        {"household_weight": [1.0, 2.0], "rent": [0.0, 9.0]}
+    )
+    tables["benunit"] = pd.DataFrame({"would_claim_uc": [True, False]})
+    for entity in tables:
+        tables[entity] = tables[entity][
+            [c for c in tables[entity].columns if c in columns]
+        ]
+    return tables
+
+
+@settings(max_examples=60, deadline=None)
+@given(
+    present=st.sets(st.sampled_from(INPUT_NAMES[:5]), min_size=1),
+    previous=st.sets(st.sampled_from(INPUT_NAMES)),
+)
+def test_newly_missing_is_missing_now_minus_missing_before(present, previous):
+    result, evidence = budget_inputs(
+        make_pair(),
+        Path("unused.h5"),
+        model_input_variables=INPUT_NAMES,
+        critical_inputs=[],
+        accepted_gaps={},
+        previous_missing_inputs=sorted(previous),
+        previous_unusable_critical=[],
+        tables=_tables(present),
+    )
+    missing = sorted(set(INPUT_NAMES) - present)
+    assert evidence["missing_inputs"] == missing
+    assert evidence["newly_missing_inputs"] == sorted(set(missing) - previous)
+
+
+def test_critical_input_regression_fails_and_standing_gaps_need_review():
+    common = dict(
+        model_input_variables=INPUT_NAMES,
+        accepted_gaps={},
+        previous_missing_inputs=None,
+    )
+    result, _ = budget_inputs(
+        make_pair(),
+        Path("x"),
+        critical_inputs=["rent", "age"],
+        previous_unusable_critical=[],
+        tables=_tables(
+            {"age", "employment_income", "household_weight", "would_claim_uc"}
+        ),
+        **common,
+    )
+    assert result.status == "fail" and "rent (missing)" in result.summary
+    degenerate = _tables(set(INPUT_NAMES))
+    degenerate["household"]["rent"] = 0.0
+    result, _ = budget_inputs(
+        make_pair(),
+        Path("x"),
+        critical_inputs=["rent"],
+        previous_unusable_critical=[],
+        tables=degenerate,
+        **common,
+    )
+    assert result.status == "fail" and "degenerate" in result.summary
+    result, _ = budget_inputs(
+        make_pair(),
+        Path("x"),
+        critical_inputs=["rent"],
+        previous_unusable_critical=["rent"],
+        tables=degenerate,
+        **common,
+    )
+    assert result.status == "needs_review"
+    result, _ = budget_inputs(
+        make_pair(),
+        Path("x"),
+        critical_inputs=["rent"],
+        previous_unusable_critical=["rent"],
+        tables=degenerate,
+        **{**common, "accepted_gaps": {"rent": "uk-data#999"}},
+    )
+    assert result.status == "pass"
+
+
+def test_critical_inputs_file_lists_real_model_inputs():
+    import json
+
+    from policyengine_uk.system import system
+
+    path = (
+        Path(gates_module.__file__).resolve().parents[1]
+        / "data"
+        / "qualification"
+        / "uk_budget_critical_inputs.json"
+    )
+    critical = json.loads(path.read_text())["critical"]
+    not_inputs = [
+        name
+        for name in critical
+        if name not in system.variables
+        or not system.variables[name].is_input_variable()
+    ]
+    assert not_inputs == []
+
+
+# --- Reform contract -----------------------------------------------------------------
+
+
+def _importer(report=None, raises=None, missing=False):
+    def runner(**kwargs):
+        if raises:
+            raise raises
+        return report
+
+    def importer(name):
+        if missing:
+            raise ModuleNotFoundError(name)
+        return SimpleNamespace(run_budget_reform_contract=runner)
+
+    return importer
+
+
+ENTRY = "policyengine.tax_benefit_models.uk.budget_reform_contract:run_budget_reform_contract"
+
+
+@pytest.mark.parametrize(
+    ("kwargs", "status"),
+    [
+        ({"missing": True}, "unavailable"),
+        ({"raises": RuntimeError("boom")}, "error"),
+        (
+            {
+                "report": {
+                    "contract_version": "1.0.0",
+                    "cases": [
+                        {
+                            "case_id": "april",
+                            "route": "wrapper.policy",
+                            "status": "pass",
+                        }
+                    ],
+                }
+            },
+            "pass",
+        ),
+        (
+            {
+                "report": {
+                    "cases": [
+                        {
+                            "case_id": "april",
+                            "route": "country.reform_dict",
+                            "status": "fail",
+                        }
+                    ]
+                }
+            },
+            "fail",
+        ),
+        (
+            {
+                "report": {
+                    "cases": [
+                        {
+                            "case_id": "api",
+                            "route": "api.sim_api",
+                            "status": "unsupported",
+                        }
+                    ]
+                }
+            },
+            "error",
+        ),
+        (
+            {
+                "report": {
+                    "cases": [
+                        {
+                            "case_id": "api",
+                            "route": "api.sim_api",
+                            "status": "unsupported",
+                            "reason": "runs in sim-api",
+                        },
+                        {
+                            "case_id": "freeze",
+                            "route": "wrapper.policy",
+                            "status": "pending",
+                            "decision_id": "d1344",
+                        },
+                    ]
+                }
+            },
+            "pass",
+        ),
+        ({"report": {"cases": []}}, "error"),
+        (
+            {
+                "report": {
+                    "cases": [{"case_id": "x", "route": "r", "status": "pass"}],
+                    "properties": [
+                        {"property_id": "baseline_isolation", "status": "fail"}
+                    ],
+                }
+            },
+            "fail",
+        ),
+    ],
+)
+def test_reform_contract_statuses(kwargs, status):
+    result, _ = reform_contract(
+        entrypoint=ENTRY,
+        dataset_path=None,
+        seed=0,
+        max_examples=5,
+        importer=_importer(**kwargs),
+    )
+    assert result.status == status, result.summary
+
+
+def test_no_contract_configured_is_unavailable():
+    assert (
+        reform_contract(entrypoint=None, dataset_path=None, seed=0, max_examples=1)[
+            0
+        ].status
+        == "unavailable"
+    )
+
+
+# --- Metrics review ------------------------------------------------------------------
+
+BOUNDS = {
+    "default": {"relative": 0.02, "absolute": 5e8},
+    "kinds": {"poverty": {"relative": 0.0, "absolute": 0.005}},
+}
+
+
+def _report(values, **extra):
+    return {
+        "status": "ok",
+        "metrics_version": "m1",
+        "partition_version": "p1",
+        "metrics": [
+            {"metric_id": mid, "year": year, "value": value, "kind": kind}
+            for (mid, year, kind), value in values.items()
+        ],
+        "identities": extra.pop("identities", []),
+        **extra,
+    }
+
+
+BASE = {
+    ("income_tax", 2027, "receipt"): 3.0e11,
+    ("relative_poverty", 2027, "poverty"): 0.17,
+}
+
+
+def test_metric_comparison_rules():
+    assert compare_metric_reports(_report(BASE), _report(BASE), BOUNDS)[0] == "pass"
+    moved = {**BASE, ("income_tax", 2027, "receipt"): 3.1e11}
+    assert (
+        compare_metric_reports(_report(moved), _report(BASE), BOUNDS)[0]
+        == "needs_review"
+    )
+    assert (
+        compare_metric_reports(
+            _report(BASE, metrics_version="m2"), _report(BASE), BOUNDS
+        )[0]
+        == "fail"
+    )
+    assert (
+        compare_metric_reports(
+            _report(BASE, partition_version="p2"), _report(BASE), BOUNDS
+        )[0]
+        == "needs_review"
+    )
+    lost = {("income_tax", 2027, "receipt"): 3.0e11}
+    assert compare_metric_reports(_report(lost), _report(BASE), BOUNDS)[0] == "fail"
+    nan = {**BASE, ("income_tax", 2027, "receipt"): float("nan")}
+    assert compare_metric_reports(_report(nan), _report(BASE), BOUNDS)[0] == "fail"
+    warned = _report(
+        BASE, identities=[{"identity_id": "inert:alcohol_duty", "status": "warn"}]
+    )
+    status, _, evidence = compare_metric_reports(warned, _report(BASE), BOUNDS)
+    assert status == "pass" and evidence["warn_identities"] == ["inert:alcohol_duty"]
+
+
+def _checks(**statuses):
+    return [
+        {"identity_id": key.replace("__", ":"), "status": value}
+        for key, value in statuses.items()
+    ]
+
+
+@pytest.mark.parametrize(
+    ("candidate", "previous", "status"),
+    [
+        # Hard checks fail whatever the previous pair did.
+        ({"finite__vat": "fail"}, {"finite__vat": "fail"}, "fail"),
+        ({"closure": "fail"}, {}, "fail"),
+        (
+            {"identity__partition_sum": "fail"},
+            {"identity__partition_sum": "pass"},
+            "fail",
+        ),
+        ({"determinism__repeat": "fail"}, {}, "fail"),
+        # Unknown check kinds are treated as hard: no silent skips.
+        ({"newkind__x": "fail"}, {"newkind__x": "fail"}, "fail"),
+        # Known-defect checks fail only as regressions.
+        (
+            {"counted_once__statutory_sick_pay": "fail"},
+            {"counted_once__statutory_sick_pay": "fail"},
+            "pass",
+        ),
+        (
+            {"counted_once__statutory_sick_pay": "fail"},
+            {"counted_once__statutory_sick_pay": "pass"},
+            "fail",
+        ),
+        ({"sign__vat": "fail"}, {}, "fail"),
+        ({"bounds__uc": "fail"}, {"bounds__uc": "fail"}, "pass"),
+        # Warnings are recorded; a check that newly warns needs review.
+        ({"inert__tobacco_duty": "warn"}, {"inert__tobacco_duty": "warn"}, "pass"),
+        (
+            {"inert__tobacco_duty": "warn"},
+            {"inert__tobacco_duty": "pass"},
+            "needs_review",
+        ),
+    ],
+)
+def test_check_classification(candidate, previous, status):
+    result = compare_metric_reports(
+        _report(BASE, identities=_checks(**candidate)),
+        _report(BASE, identities=_checks(**previous)),
+        BOUNDS,
+    )
+    assert result[0] == status, result[1]
+
+
+@settings(max_examples=150, deadline=None)
+@given(
+    changes=st.lists(
+        st.floats(min_value=-0.5, max_value=0.5, allow_nan=False),
+        min_size=2,
+        max_size=2,
+    ),
+    shrink=st.floats(min_value=0.0, max_value=1.0),
+)
+def test_shrinking_moves_never_worsens_the_status(changes, shrink):
+    order = {"pass": 0, "needs_review": 1, "fail": 2}
+    keys = list(BASE)
+
+    def candidate(scale):
+        return _report(
+            {
+                key: BASE[key] * (1 + scale * change)
+                for key, change in zip(keys, changes)
+            }
+        )
+
+    full = compare_metric_reports(candidate(1.0), _report(BASE), BOUNDS)[0]
+    smaller = compare_metric_reports(candidate(shrink), _report(BASE), BOUNDS)[0]
+    assert order[smaller] <= order[full]
+
+
+def test_metrics_gate_splits_model_and_data_steps():
+    cross = {**BASE, ("income_tax", 2027, "receipt"): 3.2e11}
+    result, evidence = metrics_review(
+        candidate_report=_report(cross),
+        previous_report=_report(BASE),
+        bounds=BOUNDS,
+        cross_report=_report(cross),
+    )
+    assert result.details == {"model_only": "needs_review", "data_only": "pass"}
+    assert result.status == "needs_review"
+    assert (
+        metrics_review(candidate_report=None, previous_report=None, bounds=BOUNDS)[
+            0
+        ].status
+        == "unavailable"
+    )
+
+
+# --- Orchestration -------------------------------------------------------------------
+
+
+@settings(max_examples=50, deadline=None)
+@given(
+    outcomes=st.lists(
+        st.sampled_from(["pass", "fail", "raise"]), min_size=1, max_size=9
+    )
+)
+def test_run_gates_returns_one_result_per_gate(outcomes):
+    def make(index, outcome):
+        def function():
+            if outcome == "raise":
+                raise RuntimeError(f"gate {index} crashed")
+            return gates_module._result(f"wrong-id-{index}", outcome, "x", {})
+
+        return (f"gate_{index}", function)
+
+    results, evidence = run_gates([make(i, o) for i, o in enumerate(outcomes)])
+    assert [r.gate_id for r in results] == [f"gate_{i}" for i in range(len(outcomes))]
+    for result, outcome in zip(results, outcomes):
+        assert result.status == ("error" if outcome == "raise" else outcome)
+    assert set(evidence) == {f"gate_{i}" for i in range(len(outcomes))}
+
+
+# --- Previous-pair runners -----------------------------------------------------------
+
+
+@settings(max_examples=15, deadline=None)
+@given(
+    present=st.sets(st.sampled_from(["age", "employment_income", "rent"]), min_size=1),
+    critical=st.lists(
+        st.sampled_from(["age", "rent", "would_claim_uc", "missing_x"]),
+        unique=True,
+        max_size=3,
+    ),
+    projected=st.lists(st.integers(2022, 2032), min_size=1, max_size=6, unique=True),
+)
+def test_inputs_runner_agrees_with_the_gates(
+    tmp_path_factory, present, critical, projected
+):
+    """Differential: the previous-pair runner and the in-process gates agree."""
+
+    import sys
+
+    from policyengine.provenance.uk_candidate import (
+        dataset_columns,
+        run_inputs_snapshot,
+    )
+
+    directory = tmp_path_factory.mktemp("runner")
+    extra = {"rent_person": [1.0, 0.0]} if "rent" in present else {}
+    path = _tiny_dataset(directory / "data.h5", year=2024, extra_person=extra)
+    inputs = [
+        "age",
+        "employment_income",
+        "rent",
+        "would_claim_uc",
+        "household_weight",
+        "missing_x",
+    ]
+    snapshot = run_inputs_snapshot(
+        sys.executable,
+        critical=critical,
+        out=directory / "snapshot.json",
+        dataset_path=path,
+        model_input_variables=inputs,
+        projected_years=projected,
+    )
+    tables = dataset_columns(path)
+    _, evidence = budget_inputs(
+        make_pair(),
+        path,
+        model_input_variables=inputs,
+        critical_inputs=critical,
+        accepted_gaps={},
+        previous_missing_inputs=None,
+        previous_unusable_critical=None,
+        tables=tables,
+    )
+    assert snapshot["missing_inputs"] == evidence["missing_inputs"]
+    assert snapshot["unusable_critical"] == evidence["unusable_critical"]
+    _, years = supported_years(
+        make_pair(),
+        path,
+        required_years=[],
+        budget_horizon_years=[],
+        previous_supported_years=None,
+        projected_years=lambda _: sorted(projected),
+    )
+    assert snapshot["supported_years"] == years["supported_years"]
+
+
+def _tool_tarball(commit="c" * 40, include_partition=True):
+    import tarfile
+
+    buffer = io.BytesIO()
+    prefix = f"policyengine-uk-{commit}"
+    files = {
+        f"{prefix}/policyengine_uk/utils/aggregate_impact/__init__.py": b"TOOL_SCHEMA = 'x/1'\n",
+        f"{prefix}/policyengine_uk/utils/aggregate_impact/api.py": b"def compute_budget_metrics(sim, **kwargs):\n    return {}\n",
+        f"{prefix}/policyengine_uk/utils/other.py": b"not copied\n",
+    }
+    if include_partition:
+        files[f"{prefix}/policyengine_uk/data/fiscal_partition.yaml"] = b"heads: []\n"
+    with tarfile.open(fileobj=buffer, mode="w:gz") as archive:
+        for name, data in files.items():
+            info = tarfile.TarInfo(name)
+            info.size = len(data)
+            archive.addfile(info, io.BytesIO(data))
+    return buffer.getvalue()
+
+
+def test_metrics_tool_is_vendored_from_one_commit(tmp_path):
+    from policyengine.provenance.uk_candidate import vendor_metrics_tool
+
+    calls = []
+
+    def get(url, timeout=None):
+        calls.append(url)
+        response = SimpleNamespace(
+            content=_tool_tarball(), raise_for_status=lambda: None
+        )
+        return response
+
+    tool = {
+        "repository": "PolicyEngine/policyengine-uk",
+        "commit": "c" * 40,
+        "path": "policyengine_uk/utils/aggregate_impact",
+    }
+    root = vendor_metrics_tool(tool, tmp_path, get=get)
+    assert calls == [
+        f"https://codeload.github.com/PolicyEngine/policyengine-uk/tar.gz/{'c' * 40}"
+    ]
+    assert sorted(p.name for p in (root / "pe_uk_aggregate_impact").iterdir()) == [
+        "__init__.py",
+        "api.py",
+    ]
+    assert (root / "fiscal_partition.yaml").read_text() == "heads: []\n"
+    assert (
+        vendor_metrics_tool(
+            tool, tmp_path, get=lambda *a, **k: pytest.fail("refetched")
+        )
+        == root
+    )
+
+
+def test_metrics_report_runner_command(tmp_path):
+    import json as _json
+
+    from policyengine.provenance.uk_candidate import METRICS_RUNNER, run_metrics_report
+
+    seen = {}
+
+    def run(command, check, cwd):
+        seen["command"] = command
+        Path(command[-1]).write_text(_json.dumps({"status": "ok", "metrics": []}))
+
+    report = run_metrics_report(
+        "/venv/bin/python",
+        tmp_path / "tool",
+        years=[2026, 2027],
+        out=tmp_path / "report.json",
+        dataset_path=tmp_path / "data.h5",
+        run=run,
+    )
+    assert report == {"status": "ok", "metrics": []}
+    python, flag, code, vendor, settings, out = seen["command"]
+    assert (python, flag, code) == ("/venv/bin/python", "-c", METRICS_RUNNER)
+    assert _json.loads(settings)["years"] == [2026, 2027]
+    assert _json.loads(settings)["run_guard"] is True
+
+
+def test_metrics_with_nan_values_fail_rather_than_crash():
+    nan = {**BASE, ("income_tax", 2027, "receipt"): float("nan")}
+    result, evidence = metrics_review(
+        candidate_report=_report(nan), previous_report=_report(BASE), bounds=BOUNDS
+    )
+    assert result.status == "fail"
+    assert result.evidence_sha256
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
new file mode 100644
index 00000000..1964fcf4
--- /dev/null
+++ b/tests/test_uk_qualification_pipeline.py
@@ -0,0 +1,566 @@
+"""Orchestration of UK candidate qualification (no network).
+
+Invariants:
+
+- resolution keeps the certified core when the model accepts it and never
+  picks a prerelease, yanked or unpublished version;
+- the decision never qualifies a pair main already certifies or one main
+  supersedes, and never repeats a terminal attempt;
+- rewriting the certified-version test constants leaves no old value behind
+  and touches only quoted literals;
+- the replay request built for a candidate is valid against the scorecard's
+  vendored schema and binds the candidate commit, wheels and dataset;
+- promotion planning readies only the selected target and closes exactly the
+  candidates it or main supersede.
+"""
+
+from __future__ import annotations
+
+import hashlib
+import json
+import shutil
+from pathlib import Path
+
+import jsonschema
+import pytest
+
+from policyengine.provenance.qualification import ReplayStatus
+from policyengine.provenance.qualification_ledger import write_json
+from policyengine.provenance.uk_qualification import (
+    accept_review,
+    assemble_receipt,
+    build_replay_request,
+    candidate_action,
+    candidate_branch,
+    certified_constant_replacements,
+    choose_core_version,
+    core_requirement,
+    latest_data_release,
+    plan_promotion,
+    read_replay,
+    resolve_candidate,
+    rewrite_certified_constants,
+)
+from tests.qualification_fixtures import (
+    HARNESS,
+    ISSUED,
+    VENDORED_SCHEMAS,
+    gates,
+    golden,
+    make_pair,
+    make_receipt,
+    sha,
+)
+
+REPO_ROOT = Path(__file__).resolve().parents[1]
+BUNDLE = json.loads(
+    (REPO_ROOT / "src/policyengine/data/bundle/manifest.json").read_text()
+)
+
+
+def _wheel(name, version, digest):
+    return {
+        "packagetype": "bdist_wheel",
+        "filename": f"{name.replace('-', '_')}-{version}-py3-none-any.whl",
+        "url": f"https://files.pythonhosted.org/packages/{name}-{version}.whl",
+        "digests": {"sha256": digest},
+    }
+
+
+MANIFEST = {
+    "schema_version": 1,
+    "data_package": {"name": "policyengine-uk-data", "version": "1.58.0"},
+    "default_datasets": {"national": "enhanced_frs_2024_25"},
+    "build": {"build_id": "policyengine-uk-data-1.58.0"},
+    "artifacts": {
+        "enhanced_frs_2024_25": {
+            "kind": "microdata",
+            "path": "enhanced_frs_2024_25.h5",
+            "repo_id": "policyengine/policyengine-uk-data-private",
+            "revision": "1.58.0",
+            "sha256": "d" * 64,
+            "size_bytes": 128369110,
+        }
+    },
+}
+
+
+def _resolver(**overrides):
+    projects = {
+        "policyengine-uk": {
+            "releases": {
+                "2.126.6": [_wheel("policyengine-uk", "2.126.6", "1" * 64)],
+                "2.126.8": [_wheel("policyengine-uk", "2.126.8", "2" * 64)],
+                "2.127.0rc1": [_wheel("policyengine-uk", "2.127.0rc1", "3" * 64)],
+                "2.127.1": [
+                    {**_wheel("policyengine-uk", "2.127.1", "4" * 64), "yanked": True}
+                ],
+            }
+        },
+        "policyengine-uk/2.126.8": {
+            "info": {"requires_dist": ["policyengine-core>=3.32.27"]}
+        },
+        "policyengine-uk/2.126.6": {
+            "info": {"requires_dist": ["policyengine-core>=3.34.0"]}
+        },
+        "policyengine-core": {
+            "releases": {
+                v: [_wheel("policyengine-core", v, v.replace(".", "")[0] * 64)]
+                for v in ("3.33.0", "3.34.0", "3.34.1", "3.35.0rc1")
+            }
+        },
+    }
+    manifest_bytes = json.dumps(MANIFEST).encode()
+    kwargs = dict(
+        current_core="3.33.0",
+        pypi_project=lambda path: projects[path],
+        hf_revision_sha=lambda repo, rev: "f" * 40,
+        hf_tags=lambda repo: ["1.57.4", "1.58.0", "v1.11.1", "version_a"],
+        hf_file=lambda repo, rev, path: manifest_bytes,
+    )
+    kwargs.update(overrides)
+    return resolve_candidate(**kwargs), manifest_bytes
+
+
+def test_resolution_picks_newest_stable_and_keeps_an_accepted_core():
+    resolved, manifest_bytes = _resolver()
+    pair = resolved.pair
+    assert pair.model.version == "2.126.8"
+    assert pair.model.wheel_sha256 == "2" * 64
+    assert pair.core.version == "3.33.0"
+    assert pair.data.release_version == "1.58.0"
+    assert pair.data.release_manifest_revision == "f" * 40
+    assert (
+        pair.data.release_manifest_sha256 == hashlib.sha256(manifest_bytes).hexdigest()
+    )
+    assert resolved.manifest_uri.startswith(
+        "hf://model/policyengine/policyengine-uk-data-private@"
+    )
+
+
+def test_resolution_moves_core_only_when_the_model_requires_it():
+    resolved, _ = _resolver(model_version="2.126.6")
+    assert resolved.pair.core.version == "3.34.1"
+
+
+def test_core_requirement_and_choice():
+    assert (
+        core_requirement(["numpy>=1", "policyengine_core>=3.32.27,<4"])
+        == "<4,>=3.32.27"
+    )
+    with pytest.raises(ValueError):
+        core_requirement(["numpy"])
+    with pytest.raises(ValueError):
+        choose_core_version("3.33.0", ">=9", [])
+
+
+def test_latest_data_release_ignores_non_version_tags():
+    assert latest_data_release(["1.57.4", "1.58.0", "v1.11.1", "version_a"]) == "1.58.0"
+
+
+def test_resolution_refuses_unpublished_versions():
+    with pytest.raises(ValueError):
+        _resolver(model_version="9.9.9")
+
+
+def test_actions(tmp_path):
+    current = BUNDLE["data_releases"]["uk"]
+    certified = make_pair(
+        model=current["model_package"]["version"],
+        data=current["data_package"]["version"],
+        core=BUNDLE["packages"]["policyengine-core"]["version"],
+        dataset_sha=current["certified_data_artifact"]["sha256"],
+    )
+    assert (
+        candidate_action(certified, BUNDLE, tmp_path, base_commit="a" * 40)[0]
+        == "already_certified"
+    )
+    older = make_pair(model="2.100.0", data="1.50.0", core="3.30.0")
+    assert candidate_action(older, BUNDLE, tmp_path, base_commit="a" * 40)[0] == "stale"
+    newer = make_pair(model="2.200.0", data="1.58.0", core="3.33.0")
+    assert (
+        candidate_action(newer, BUNDLE, tmp_path, base_commit="a" * 40)[0] == "qualify"
+    )
+    rejected = make_receipt(pair=newer, gate_results=gates(wheel_hashes="fail"))
+    write_json(
+        tmp_path / "uk" / newer.pair_id / "qualification_receipt.json",
+        rejected.canonical_payload(),
+    )
+    assert (
+        candidate_action(newer, BUNDLE, tmp_path, base_commit="a" * 40)[0]
+        == "duplicate"
+    )
+    assert (
+        candidate_action(newer, BUNDLE, tmp_path, base_commit="a" * 40, force=True)[0]
+        == "qualify"
+    )
+
+
+def test_incomplete_pairs_requalify_on_a_new_base_only(tmp_path):
+    pair = make_pair(model="2.200.0")
+    incomplete = make_receipt(
+        pair=pair, gate_results=gates(reform_contract="unavailable")
+    )
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        incomplete.canonical_payload(),
+    )
+    (tmp_path / "uk" / pair.pair_id / "attempts" / ("a" * 12)).mkdir(parents=True)
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit="a" * 40)[0] == "duplicate"
+    )
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit="b" * 40)[0] == "qualify"
+    )
+
+
+def _new_record(old):
+    new = json.loads(json.dumps(old))
+    new["model_package"]["version"] = "2.126.8"
+    new["certification"]["built_with_model_version"] = "2.126.0"
+    new["certification"]["data_build_id"] = "policyengine-uk-data-1.59.0"
+    new["data_package"]["version"] = "1.59.0"
+    new["data_package"]["release_manifest_revision"] = "1" * 40
+    return new
+
+
+def test_constant_rewrite_leaves_no_old_values(tmp_path):
+    for relative in (
+        "tests/test_models.py",
+        "tests/test_release_manifests.py",
+        "tests/test_uk_regions.py",
+    ):
+        (tmp_path / relative).parent.mkdir(parents=True, exist_ok=True)
+        shutil.copy(REPO_ROOT / relative, tmp_path / relative)
+    old = BUNDLE["data_releases"]["uk"]
+    new = _new_record(old)
+    replacements = certified_constant_replacements(old, new)
+    changed = rewrite_certified_constants(tmp_path, replacements)
+    assert set(changed) == {
+        "tests/test_models.py",
+        "tests/test_release_manifests.py",
+        "tests/test_uk_regions.py",
+    }
+    for relative in changed:
+        text = (tmp_path / relative).read_text()
+        for before, after in replacements:
+            assert f'"{before}"' not in text and f'@{before}"' not in text
+    manifests = (tmp_path / "tests/test_release_manifests.py").read_text()
+    assert 'UK_MODEL_VERSION = "2.126.8"' in manifests
+    assert 'UK_DATA_RELEASE_PATH = "releases/1.59.0/release_manifest.json"' in manifests
+    assert 'UK_DATA_RELEASE_REVISION = "' + "1" * 40 + '"' in manifests
+    assert rewrite_certified_constants(tmp_path, replacements) == []
+
+
+def test_replay_request_is_valid_for_the_scorecard():
+    pair = make_pair()
+    release_bundle = dict(
+        golden("qualification_request_golden")["candidate"]["expected_release_bundle"]
+    )
+    request = build_replay_request(
+        pair, HARNESS, release_bundle=release_bundle, issued_by=ISSUED
+    )
+    schema = json.loads(
+        (VENDORED_SCHEMAS / "qualification_request.v1.json").read_text()
+    )
+    jsonschema.Draft202012Validator(schema).validate(request.document())
+    candidate = request.document()["candidate"]
+    assert candidate["policyengine"]["source"] == {
+        "git": {
+            "repository": "PolicyEngine/policyengine.py",
+            "commit": HARNESS.git_commit,
+        }
+    }
+    assert candidate["policyengine_uk"]["wheel_sha256"] == pair.model.wheel_sha256
+    assert candidate["data"]["sha256"] == pair.data.dataset_sha256
+    assert request.document()["requested_by"]["pair_id"] == pair.pair_id
+    again = build_replay_request(
+        pair, HARNESS, release_bundle=release_bundle, issued_by=ISSUED
+    )
+    assert again.request_id == request.request_id
+
+
+def test_reading_replay_state():
+    pair = make_pair()
+    request = build_replay_request(
+        pair,
+        HARNESS,
+        release_bundle=golden("qualification_request_golden")["candidate"][
+            "expected_release_bundle"
+        ],
+        issued_by=ISSUED,
+    )
+    gate, status, receipt = read_replay(
+        request, fetch=lambda ref, path: None, state_ref="replay-state"
+    )
+    assert gate.status == "unavailable" and status is None
+    running = ReplayStatus.model_validate(
+        {
+            "schema": "policyengine.uk-replay-status/v1",
+            "request_id": request.request_id,
+            "status": "running",
+            "history": [
+                {
+                    "status": "running",
+                    "at": "2026-10-15T10:00:00Z",
+                    "run_url": "https://github.com/PolicyEngine/policyengine-scorecard/actions/runs/3",
+                }
+            ],
+        }
+    ).document()
+    gate, status, _ = read_replay(
+        request,
+        fetch=lambda ref, path: (
+            json.dumps(running).encode() if path.endswith("STATUS.json") else None
+        ),
+        state_ref="replay-state",
+    )
+    assert gate.status == "unavailable" and status.status == "running"
+    terminal = {
+        **running,
+        "status": "complete",
+        "receipt_sha256": "a" * 64,
+        "receipt_commit": "c" * 40,
+    }
+    gate, _, _ = read_replay(
+        request,
+        fetch=lambda ref, path: (
+            json.dumps(terminal).encode() if path.endswith("STATUS.json") else None
+        ),
+        state_ref="replay-state",
+    )
+    assert gate.status == "fail" and "no REPLAY_RECEIPT.json" in gate.summary
+
+
+def test_assembled_receipt_without_replay_is_incomplete():
+    pair = make_pair()
+    local = [gate for gate in gates() if gate.gate_id != "replay"]
+    receipt = assemble_receipt(
+        pair,
+        HARNESS,
+        local,
+        issued_by=ISSUED,
+        completed_at="2026-10-15T10:00:00Z",
+        previous=None,
+        replay=None,
+    )
+    assert receipt.verdict == "incomplete"
+    assert [gate.gate_id for gate in receipt.gates] == [gate.gate_id for gate in local]
+
+
+def test_acceptance_is_bound_to_the_receipt():
+    receipt = make_receipt(gate_results=gates(metrics_review="needs_review"))
+    with pytest.raises(ValueError):
+        accept_review(
+            receipt,
+            reviewer="maria",
+            accepted_receipt_sha256=sha("1"),
+            explanation="x",
+            accepted_at="t",
+        )
+    reviewed = accept_review(
+        receipt,
+        reviewer="maria",
+        accepted_receipt_sha256=receipt.unreviewed_sha256,
+        explanation="Council tax move follows the 2025-26 band revaluation in uk-data.",
+        accepted_at="2026-10-16T09:00:00Z",
+    )
+    assert reviewed.promotable
+    with pytest.raises(ValueError):
+        accept_review(
+            make_receipt(),
+            reviewer="m",
+            accepted_receipt_sha256=sha("1"),
+            explanation="x",
+            accepted_at="t",
+        )
+
+
+def test_promotion_plan():
+    current = (
+        BUNDLE["data_releases"]["uk"]["model_package"]["version"],
+        BUNDLE["data_releases"]["uk"]["data_package"]["version"],
+        BUNDLE["packages"]["policyengine-core"]["version"],
+    )
+    newest = make_receipt(
+        pair=make_pair(model="2.200.0", data=current[1], core=current[2])
+    )
+    older = make_receipt(
+        pair=make_pair(model="2.199.0", data=current[1], core=current[2])
+    )
+    rejected = make_receipt(
+        pair=make_pair(model="2.201.0", data=current[1], core=current[2]),
+        gate_results=gates(replay="fail"),
+    )
+    stale = make_receipt(pair=make_pair(model="2.0.0", data="1.0.0", core="3.0.0"))
+    branches = [candidate_branch(r.pair) for r in (newest, older, rejected, stale)] + [
+        "candidate/uk/unknown"
+    ]
+    plan = plan_promotion([newest, older, rejected, stale], BUNDLE, branches)
+    assert plan.target == newest
+    assert plan.ready_branch == candidate_branch(newest.pair)
+    assert plan.close_branches == sorted(
+        [candidate_branch(older.pair), candidate_branch(stale.pair)]
+    )
+    assert candidate_branch(rejected.pair) not in plan.close_branches
+
+
+# --- Attempt lifecycle -----------------------------------------------------------------
+
+
+def test_attempt_lifecycle(tmp_path):
+    from policyengine.provenance.qualification import GateResult
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        attempt_is_waiting_for_replay,
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    pair = make_pair()
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, "abcdef123456")
+    stage_attempt(
+        attempt,
+        {
+            "pair": pair.canonical_payload(),
+            "pair_id": pair.pair_id,
+            "previous_certificate": None,
+        },
+        HARNESS,
+    )
+    local = [gate for gate in gates() if gate.gate_id != "replay"]
+    write_gate_results(attempt, local, {gate.gate_id: {"ok": True} for gate in local})
+    assert not attempt_is_waiting_for_replay(attempt)
+    receipt = finalize_attempt(
+        attempt, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T10:00:00Z"
+    )
+    assert receipt.verdict == "incomplete"  # the replay never ran
+    assert (
+        read_json(tmp_path / "uk" / pair.pair_id / "qualification_receipt.json")[
+            "verdict"
+        ]
+        == "incomplete"
+    )
+
+    request = build_replay_request(
+        pair,
+        HARNESS,
+        release_bundle=golden("qualification_request_golden")["candidate"][
+            "expected_release_bundle"
+        ],
+        issued_by=ISSUED,
+    )
+    write_json(attempt / "replay" / "request.json", request.document())
+    assert attempt_is_waiting_for_replay(attempt)
+    write_json(
+        attempt / "replay" / "replay.result.json",
+        GateResult(gate_id="replay", status="pass", summary="ok").canonical_payload(),
+    )
+    assert not attempt_is_waiting_for_replay(attempt)
+    final = finalize_attempt(
+        attempt, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    assert final.verdict == "qualified"
+    assert final.replay.request_id == request.request_id
+
+
+# --- Release dispatch ----------------------------------------------------------------
+
+
+def test_release_payload_keeps_version_first_and_carries_identity():
+    from policyengine.provenance.receipt import certificate_sha256
+    from policyengine.provenance.uk_qualification import release_dispatch_payload
+
+    version = BUNDLE["policyengine_version"]
+    payload = release_dispatch_payload(BUNDLE, version=version)
+    assert payload["event_type"] == "policyengine-release"
+    body = payload["client_payload"]
+    assert list(body)[0] == "version" and body["version"] == version
+    uk = body["bundle"]["uk"]
+    record = BUNDLE["data_releases"]["uk"]
+    assert uk["model_version"] == record["model_package"]["version"]
+    assert uk["dataset_sha256"] == record["certified_data_artifact"]["sha256"]
+    assert uk["certificate_sha256"] == certificate_sha256(record)
+    assert body["qualification"] is None  # the committed pair was not auto-qualified
+    assert len(body) <= 10  # repository_dispatch limit on top-level keys
+    with pytest.raises(ValueError):
+        release_dispatch_payload(BUNDLE, version="0.0.0")
+
+
+def test_release_payload_names_the_qualification_receipt():
+    from policyengine.provenance.uk_qualification import release_dispatch_payload
+
+    bundle = json.loads(json.dumps(BUNDLE))
+    receipt = make_receipt()
+    bundle["data_releases"]["uk"]["certification"].update(
+        compatibility_basis="qualified_exact_pair",
+        qualification_pair_id=receipt.pair_id,
+    )
+    payload = release_dispatch_payload(
+        bundle,
+        version=bundle["policyengine_version"],
+        fetch_receipt=lambda country, pair_id: receipt,
+    )
+    assert payload["client_payload"]["qualification"] == {
+        "uk": {
+            "pair_id": receipt.pair_id,
+            "verdict": "qualified",
+            "receipt_sha256": receipt.receipt_sha256,
+        }
+    }
+
+
+def test_released_bundle_request_is_valid_for_the_scorecard():
+    from policyengine.provenance.uk_qualification import released_bundle_request
+
+    record = BUNDLE["data_releases"]["uk"]
+    dataset = record["default_dataset"]
+    manifest = {
+        "schema_version": 1,
+        "data_package": {
+            "name": "policyengine-uk-data",
+            "version": record["data_package"]["version"],
+        },
+        "default_datasets": {"national": dataset},
+        "artifacts": {
+            dataset: {
+                "kind": "microdata",
+                "path": record["datasets"][dataset]["path"],
+                "repo_id": record["datasets"][dataset]["repo_id"],
+                "revision": record["datasets"][dataset]["revision"],
+                "sha256": record["datasets"][dataset]["sha256"],
+                "size_bytes": 128369110,
+            }
+        },
+    }
+    core = BUNDLE["packages"]["policyengine-core"]["version"]
+    request = released_bundle_request(
+        BUNDLE,
+        version=BUNDLE["policyengine_version"],
+        wheel_sha256=sha("7"),
+        packaged_manifest_sha256=sha("8"),
+        release_bundle=golden("qualification_request_golden")["candidate"][
+            "expected_release_bundle"
+        ],
+        hf_file=lambda repo, rev, path: json.dumps(manifest).encode(),
+        pypi_project=lambda name: {
+            "releases": {core: [_wheel("policyengine-core", core, sha("6"))]}
+        },
+        requested_by={
+            "repository": "PolicyEngine/policyengine.py",
+            "workflow_run_id": 5,
+            "commit": "e" * 40,
+        },
+    )
+    schema = json.loads(
+        (VENDORED_SCHEMAS / "qualification_request.v1.json").read_text()
+    )
+    jsonschema.Draft202012Validator(schema).validate(request.document())
+    assert request.kind == "released_bundle"
+    assert request.document()["candidate"]["policyengine"]["source"] == {
+        "pypi": {"wheel_sha256": sha("7")}
+    }

From d8100666bc3920a0af8f4150000def709ff63341 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 15:48:12 -0400
Subject: [PATCH 03/45] Verify wheels through the shared provenance.wheels
 module

The receipt builder now verifies installed files against wheel RECORDs
itself, so the qualification gates use the same implementation and hand
the receipt builder wheel paths rather than asserted hashes.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py | 104 ++------------------
 tests/test_uk_candidate_gates.py            |   8 +-
 2 files changed, 15 insertions(+), 97 deletions(-)

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index aa8f40c5..720c6669 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -14,15 +14,12 @@
 
 from __future__ import annotations
 
-import base64
-import csv
 import hashlib
 import importlib
 import io
 import json
 import math
 import traceback
-import zipfile
 from collections.abc import Callable, Iterable, Mapping, Sequence
 from importlib import metadata as importlib_metadata
 from pathlib import Path
@@ -39,15 +36,14 @@
     QualificationHarness,
 )
 from policyengine.provenance.receipt import content_sha256
+from policyengine.provenance.wheels import (
+    verify_installed_against_wheel,
+)
 from policyengine.utils.hashing import sha256_file
 
 Evidence = dict[str, Any]
 GateOutcome = tuple[GateResult, Evidence]
 
-#: Files an installer adds to a distribution that are not in the wheel RECORD.
-INSTALLER_FILES = frozenset(
-    {"INSTALLER", "REQUESTED", "direct_url.json", "uv_cache.json"}
-)
 UK_SINGLE_YEAR_KEYS = ("time_period", "person", "benunit", "household")
 ENTITY_TABLES = ("person", "benunit", "household")
 
@@ -156,89 +152,6 @@ def installed_versions(
 # --- 2. Wheel hashes -----------------------------------------------------------
 
 
-def record_digest_to_hex(value: str) -> str:
-    """Convert a RECORD ``sha256=`` digest to hex."""
-
-    algorithm, _, encoded = value.partition("=")
-    if algorithm != "sha256":
-        raise ValueError(f"Unsupported RECORD hash {algorithm!r}.")
-    padded = encoded + "=" * (-len(encoded) % 4)
-    return base64.urlsafe_b64decode(padded).hex()
-
-
-def parse_record(text: str) -> dict[str, Optional[str]]:
-    """``{path: hex sha256 or None}`` from a RECORD file."""
-
-    entries: dict[str, Optional[str]] = {}
-    for row in csv.reader(io.StringIO(text)):
-        if not row:
-            continue
-        path, digest = row[0], (row[1] if len(row) > 1 else "")
-        entries[path] = record_digest_to_hex(digest) if digest else None
-    return entries
-
-
-def wheel_record(wheel_path: Path) -> dict[str, Optional[str]]:
-    with zipfile.ZipFile(wheel_path) as archive:
-        names = [
-            name for name in archive.namelist() if name.endswith(".dist-info/RECORD")
-        ]
-        if len(names) != 1:
-            raise ValueError(f"{wheel_path.name} has {len(names)} RECORD files.")
-        return parse_record(archive.read(names[0]).decode("utf-8"))
-
-
-def verify_installed_against_wheel(
-    name: str, wheel_path: Path, *, metadata: Any = importlib_metadata
-) -> Evidence:
-    """Check every hashed wheel file is installed with the same bytes.
-
-    Returns evidence; raises nothing. ``problems`` lists every mismatch.
-    """
-
-    expected = wheel_record(wheel_path)
-    distribution = metadata.distribution(name)
-    installed: dict[str, Optional[str]] = {}
-    for file in distribution.files or []:
-        installed[str(file)] = (
-            record_digest_to_hex(f"{file.hash.mode}={file.hash.value}")
-            if file.hash is not None
-            else None
-        )
-    problems: list[str] = []
-    verified = 0
-    for path, digest in sorted(expected.items()):
-        if digest is None:
-            continue
-        if installed.get(path, "absent") != digest:
-            problems.append(f"{path}: installed RECORD differs from the wheel")
-            continue
-        located = Path(distribution.locate_file(path))
-        if not located.is_file():
-            problems.append(f"{path}: missing on disk")
-            continue
-        if sha256_file(located) != digest:
-            problems.append(f"{path}: bytes differ from the wheel")
-            continue
-        verified += 1
-    extra = sorted(
-        path
-        for path in installed
-        if path not in expected
-        and not path.endswith(".pyc")
-        and Path(path).name not in INSTALLER_FILES
-        and not path.endswith(".dist-info/RECORD")
-    )
-    problems.extend(f"{path}: installed but not in the wheel" for path in extra)
-    return {
-        "wheel": wheel_path.name,
-        "wheel_sha256": sha256_file(wheel_path),
-        "files_verified": verified,
-        "unexpected_installed_files": extra,
-        "problems": problems,
-    }
-
-
 def wheel_hashes(
     pair: CandidatePair,
     *,
@@ -280,12 +193,15 @@ def wheel_hashes(
     )
 
 
-def verified_package_hashes(pair: CandidatePair) -> dict[str, tuple[str, str]]:
-    """``package_hashes`` for ``build_execution_receipt`` after ``wheel_hashes`` passes."""
+def receipt_wheel_paths(
+    pair: CandidatePair, wheel_paths: Mapping[str, Path]
+) -> dict[str, Path]:
+    """``wheel_paths`` for ``build_execution_receipt``, which re-verifies them."""
 
     return {
-        pair.model.name: (pair.model.wheel_sha256, "installed_record_verified"),
-        pair.core.name: (pair.core.wheel_sha256, "installed_record_verified"),
+        package.name: Path(wheel_paths[package.name])
+        for package in (pair.model, pair.core)
+        if package.name in wheel_paths
     }
 
 
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index bca2a2ff..98c84c0d 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -36,14 +36,16 @@
     dataset_bytes,
     installed_versions,
     metrics_review,
-    parse_record,
-    record_digest_to_hex,
     reform_contract,
     run_gates,
     supported_years,
-    verify_installed_against_wheel,
     wheel_hashes,
 )
+from policyengine.provenance.wheels import (
+    parse_record,
+    record_digest_to_hex,
+    verify_installed_against_wheel,
+)
 from tests.qualification_fixtures import HARNESS, make_pair
 
 # --- Installed versions --------------------------------------------------------

From d3bde21163c6b21077fe3a7d78140ce279968dc7 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 16:04:00 -0400
Subject: [PATCH 04/45] Use the reform contract runner's default sample size

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/data/qualification/uk.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index c0718585..e355d94d 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -6,7 +6,8 @@
   "reform_contract": {
     "entrypoint": "policyengine.tax_benefit_models.uk.budget_reform_contract:run_budget_reform_contract",
     "seed": 0,
-    "max_examples": 50
+    "max_examples": 20,
+    "_comment": "W1's runner (policyengine.py#577); its pass also needs policyengine-uk#2305 and policyengine.py#575, so certified 2.125.1 fails the dated cases by design."
   },
   "metrics": {
     "tool": {

From a0872762d5313d022faca8e35ffab94e10e558a4 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 16:11:35 -0400
Subject: [PATCH 05/45] Re-pin the scorecard replay schemas at 91f46c1

The scorecard relaxed two rules: requested_by.workflow_run_id is optional,
and a failed receipt may carry no variant or execution when it failed
before the candidate was identified. The mirrors follow, and such a
receipt fails the replay gate.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 .../vendor/policyengine-scorecard/README.md   |  2 +-
 .../qualification_request.v1.json             |  2 +-
 .../replay_receipt.v1.json                    | 28 ++++++++++++++---
 src/policyengine/provenance/qualification.py  | 29 ++++++++++++++----
 tests/test_qualification_contracts.py         | 30 +++++++++++++++++++
 5 files changed, 79 insertions(+), 12 deletions(-)

diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
index 23fd1b7c..e3fe467b 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
@@ -1,7 +1,7 @@
 # Vendored policyengine-scorecard schemas
 
 Copied unchanged from PolicyEngine/policyengine-scorecard, branch
-`w6/replay-variants`, commit `62704be` (`docs/uk_replay/schemas/`): the v1
+`w6/replay-variants`, commit `91f46c1` (`docs/uk_replay/schemas/`): the v1
 pre-promotion replay interface between policyengine.py qualification (W4)
 and the replay corpus (W6). `policyengine.provenance.qualification` mirrors
 them, and `tests/test_qualification_contracts.py` checks the mirrors and the
diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
index 735b66c6..16921af5 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
@@ -105,7 +105,7 @@
   "requested_by": {
    "type": "object",
    "additionalProperties": true,
-   "required": ["repository", "workflow_run_id", "commit"],
+   "required": ["repository", "commit"],
    "properties": {
     "repository": {"type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"},
     "workflow_run_id": {"type": "integer", "minimum": 1},
diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
index c5d8d9aa..f127f28a 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
@@ -429,10 +429,7 @@
    "if": {
     "properties": {
      "status": {
-      "enum": [
-       "complete",
-       "failed"
-      ]
+      "const": "complete"
      }
     }
    },
@@ -475,6 +472,29 @@
      }
     }
    }
+  },
+  {
+   "if": {
+    "properties": {
+     "status": {
+      "const": "failed"
+     }
+    }
+   },
+   "then": {
+    "properties": {
+     "rejection": {
+      "type": "null"
+     },
+     "integrity": {
+      "properties": {
+       "status": {
+        "const": "failed"
+       }
+      }
+     }
+    }
+   }
   }
  ],
  "$defs": {
diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index fa300731..141b35b0 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -440,7 +440,7 @@ def _required_bundle_fields(
 
 class RequestedBy(_Open):
     repository: str = Field(pattern=r"^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$")
-    workflow_run_id: int = Field(ge=1)
+    workflow_run_id: Optional[int] = Field(default=None, ge=1)
     run_attempt: Optional[int] = Field(default=None, ge=1)
     commit: str = Field(pattern=_SHA1)
 
@@ -690,15 +690,19 @@ def _status_shape(self) -> ReplayReceipt:
                 raise ValueError(
                     "A rejected receipt has a rejection and no corpus or diff."
                 )
-        else:
+        elif self.status == "complete":
             if (
                 self.rejection is not None
                 or self.variant_id is None
                 or self.execution is None
             ):
-                raise ValueError(
-                    f"A {self.status} receipt has a variant and an execution."
-                )
+                raise ValueError("A complete receipt has a variant and an execution.")
+        # A failed receipt can come from a step before the candidate's
+        # identity was known (for example a download error).
+        elif self.rejection is not None or self.integrity.status != "failed":
+            raise ValueError(
+                "A failed receipt has no rejection and a failed integrity."
+            )
         if self.status == "complete" and (
             self.integrity.status not in ("complete", "incomplete")
             or self.corpus is None
@@ -759,7 +763,20 @@ def evaluate_replay_receipt(
         )
 
     execution = receipt.execution
-    assert execution is not None
+    if execution is None:
+        codes = sorted({failure.code for failure in receipt.integrity.failures})
+        return GateResult(
+            gate_id="replay",
+            status="fail",
+            summary="Replay failed before the candidate was identified: "
+            + (", ".join(codes) or "no failure codes"),
+            details={
+                **details,
+                "integrity_failures": [
+                    failure.document() for failure in receipt.integrity.failures
+                ],
+            },
+        )
     candidate = request.candidate
     mismatches: list[str] = []
     packages = {
diff --git a/tests/test_qualification_contracts.py b/tests/test_qualification_contracts.py
index 599cccdf..f46ae768 100644
--- a/tests/test_qualification_contracts.py
+++ b/tests/test_qualification_contracts.py
@@ -286,6 +286,7 @@ def test_golden_receipt_digest_matches_received_bytes():
         lambda r: r["candidate"]["expected_release_bundle"].pop("model_version"),
     ),
     ("bad commit", lambda r: r["requested_by"].update(commit="abc")),
+    ("missing commit", lambda r: r["requested_by"].pop("commit")),
 ]
 
 
@@ -444,3 +445,32 @@ def test_status_must_name_terminal_receipt():
                 ],
             }
         )
+
+
+def test_requests_without_a_run_id_are_valid_as_in_the_schema():
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["requested_by"].pop("workflow_run_id")
+    _validator("qualification_request.v1.json").validate(raw)
+    assert ReplayQualificationRequest.model_validate(raw).document() == raw
+
+
+def test_early_failure_receipt_fails_the_gate():
+    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    doc.update(
+        status="failed",
+        variant_id=None,
+        variant_identity_sha256=None,
+        execution=None,
+        corpus=None,
+        diff=None,
+    )
+    doc["integrity"] = {
+        "status": "failed",
+        "failures": [
+            {"code": "wheel_download_failed", "detail": "pip download failed"}
+        ],
+    }
+    sealed = _sealed(doc)
+    _validator("replay_receipt.v1.json").validate(sealed)
+    gate = _gate(sealed)
+    assert gate.status == "fail" and "wheel_download_failed" in gate.summary

From ca3840d2f25fd63ff78af6070331f762c76c2241 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 17:06:32 -0400
Subject: [PATCH 06/45] Gate on the whole reform contract report, bound to the
 candidate

The reform contract gate now fails on any failing or erroring population
check as well as cases and properties, and treats a report as an error
unless it is a full run of this candidate: sampled properties ran, the
population checks ran when a dataset was given, the reported versions,
dataset digest, seed and sample size are the ones requested, and the
runner's own holds and summary agree with its rows. Tests use W1's real
reports (pinned policyengine-uk 2.125.1 fails on its 101 defects). The
wheel gate's summary reports the archive-member check too.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py   |  122 +-
 tests/fixtures/uk_contract/README.md          |   10 +
 .../pinned_uk_2.125.1_defects.json            | 2050 +++++++++++++++++
 .../population_pass_max_examples_0.json       |  161 ++
 tests/test_uk_candidate_gates.py              |  138 ++
 5 files changed, 2456 insertions(+), 25 deletions(-)
 create mode 100644 tests/fixtures/uk_contract/README.md
 create mode 100644 tests/fixtures/uk_contract/pinned_uk_2.125.1_defects.json
 create mode 100644 tests/fixtures/uk_contract/population_pass_max_examples_0.json

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 720c6669..e7af2a9d 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -183,12 +183,14 @@ def wheel_hashes(
     if problems:
         return _result("wheel_hashes", "fail", "; ".join(problems[:10]), evidence)
     counts = ", ".join(
-        f"{name} {item['files_verified']} files" for name, item in evidence.items()
+        f"{name}: {item['archive_members_verified']} wheel members, "
+        f"{item['files_verified']} installed files"
+        for name, item in evidence.items()
     )
     return _result(
         "wheel_hashes",
         "pass",
-        f"Installed files match the pinned PyPI wheels ({counts}).",
+        f"The pinned PyPI wheels match their RECORDs and the installed files ({counts}).",
         evidence,
     )
 
@@ -617,15 +619,38 @@ def _load_entrypoint(
     return function
 
 
+#: Report sections: the key that names each row, and what a row is called.
+_CONTRACT_SECTIONS = (
+    ("cases", "case_id", "case"),
+    ("properties", "property_id", "property"),
+    ("population", "check_id", "population check"),
+)
+_CONTRACT_STATUSES = ("pass", "fail", "error", "unsupported", "pending")
+
+
 def reform_contract(
     *,
     entrypoint: Optional[str],
     dataset_path: Optional[Path],
     seed: int,
     max_examples: int,
+    expected_versions: Optional[Mapping[str, str]] = None,
+    expected_dataset_sha256: Optional[str] = None,
     importer: Callable[[str], Any] = importlib.import_module,
 ) -> GateOutcome:
-    """Run the Budget reform contract (W1) and gate on its cases."""
+    """Run the Budget reform contract (W1) on every route and gate on its report.
+
+    ``fail`` when any case, sampled property or population check fails or
+    errors. ``error`` when the report cannot be trusted as a full run of this
+    candidate:
+    - a pending row lacks its ``decision_id``, or an unsupported case or
+      population check lacks its ``reason``;
+    - a sampled property did not run;
+    - population checks are missing although a dataset was given;
+    - the report names other versions, another dataset, seed or sample size
+      than requested;
+    - its own ``holds`` or ``summary`` disagrees with its rows.
+    """
 
     if not entrypoint:
         return _result(
@@ -657,40 +682,81 @@ def reform_contract(
             f"The reform contract raised {type(exc).__name__}: {exc}",
             {"entrypoint": entrypoint, "traceback": traceback.format_exc()},
         )
-    report = json.loads(json.dumps(report, default=str))
-    failures, malformed, pending, unsupported = [], [], [], []
-    for case in report.get("cases", []):
-        status = case.get("status")
-        label = f"{case.get('case_id')}@{case.get('route')}"
-        if status in ("fail", "error"):
-            failures.append(label)
-        elif status == "unsupported":
-            if not case.get("reason"):
-                malformed.append(f"{label} is unsupported without a reason")
-            unsupported.append(label)
-        elif status == "pending":
-            if not case.get("decision_id"):
-                malformed.append(f"{label} is pending without a decision_id")
-            pending.append(label)
-        elif status != "pass":
-            malformed.append(f"{label} has unknown status {status!r}")
-    for prop in report.get("properties", []):
-        if prop.get("status") not in ("pass", "pending"):
-            failures.append(f"property {prop.get('property_id')}")
+    report = json.loads(json.dumps(_json_safe(report), default=str))
+    failures: list[str] = []
+    malformed: list[str] = []
+    pending: list[str] = []
+    unsupported: list[str] = []
+    counts = dict.fromkeys(_CONTRACT_STATUSES, 0)
+    for section, key, noun in _CONTRACT_SECTIONS:
+        for row in report.get(section) or []:
+            status = row.get("status")
+            label = f"{noun} {row.get(key)}" + (
+                f"@{row['route']}" if row.get("route") else ""
+            )
+            if status in counts:
+                counts[status] += 1
+            if status in ("fail", "error"):
+                failures.append(label)
+            elif status == "pending":
+                if not row.get("decision_id"):
+                    malformed.append(f"{label} is pending without a decision_id")
+                pending.append(label)
+            elif status == "unsupported":
+                if section == "properties":
+                    malformed.append(
+                        f"{label} did not run: {row.get('reason') or 'no reason given'}"
+                    )
+                elif not row.get("reason"):
+                    malformed.append(f"{label} is unsupported without a reason")
+                unsupported.append(label)
+            elif status != "pass":
+                malformed.append(f"{label} has unknown status {status!r}")
     if not report.get("cases"):
         malformed.append("the report has no cases")
+    if dataset_path is not None and not report.get("population"):
+        malformed.append("a dataset was given but no population checks ran")
+    for field, requested in (("seed", seed), ("max_examples", max_examples)):
+        if field in report and report[field] != requested:
+            malformed.append(f"the report ran {field}={report[field]}, not {requested}")
+    reported_versions = report.get("versions") or {}
+    for package, version in (expected_versions or {}).items():
+        if reported_versions.get(package) != version:
+            malformed.append(
+                f"the report ran {package} {reported_versions.get(package)}, "
+                f"not the candidate's {version}"
+            )
+    if expected_dataset_sha256 is not None:
+        reported = (report.get("dataset") or {}).get("sha256")
+        if reported != expected_dataset_sha256:
+            malformed.append(
+                f"the report ran dataset {reported}, not the candidate's "
+                f"{expected_dataset_sha256}"
+            )
+    if "holds" in report and report["holds"] != (
+        counts["fail"] == 0 and counts["error"] == 0
+    ):
+        malformed.append("the report's holds disagrees with its rows")
+    summary = report.get("summary")
+    if (
+        isinstance(summary, Mapping)
+        and {status: summary.get(status, 0) for status in _CONTRACT_STATUSES} != counts
+    ):
+        malformed.append("the report's summary disagrees with its rows")
     details = {
         "contract_id": report.get("contract_id"),
         "contract_version": report.get("contract_version"),
         "report_sha256": evidence_sha256(report),
+        "counts": counts,
         "pending": pending,
         "unsupported": unsupported,
+        "problems": malformed,
     }
     if failures:
         return _result(
             "reform_contract",
             "fail",
-            f"{len(failures)} contract case(s) failed: {', '.join(failures[:8])}",
+            f"{len(failures)} contract row(s) failed: {', '.join(failures[:8])}",
             report,
             details,
         )
@@ -701,7 +767,8 @@ def reform_contract(
     return _result(
         "reform_contract",
         "pass",
-        f"Contract {details['contract_version']}: every case passed"
+        f"Contract {details['contract_version']}: every case, property and "
+        f"population check passed ({counts['pass']})"
         + (f"; {len(pending)} pending a methodology call" if pending else "")
         + (f"; {len(unsupported)} unsupported by design" if unsupported else "")
         + ".",
@@ -1386,6 +1453,11 @@ def gate_contract() -> GateOutcome:
             dataset_path=dataset(),
             seed=int(settings.get("seed", 0)),
             max_examples=int(settings.get("max_examples", 50)),
+            expected_versions={
+                pair.model.name: pair.model.version,
+                pair.core.name: pair.core.version,
+            },
+            expected_dataset_sha256=pair.data.dataset_sha256,
         )
 
     def gate_metrics() -> GateOutcome:
diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
new file mode 100644
index 00000000..94ee01dd
--- /dev/null
+++ b/tests/fixtures/uk_contract/README.md
@@ -0,0 +1,10 @@
+# UK Budget reform contract reports
+
+Real reports from the UK Budget reform contract runner (workstream W1,
+`policyengine.tax_benefit_models.uk.budget_reform_contract`, PolicyEngine/policyengine.py#577),
+run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate_gates.py` read them.
+
+- `pinned_uk_2.125.1_defects.json`: every case on policyengine-uk 2.125.1, the pinned model at the time, with `max_examples=2` and no dataset. The 66 failures and 35 errors are the dated-reform defects the contract was written to catch.
+- `population_pass_max_examples_0.json`: population checks only, on a 1,000-household subsample of the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`), policyengine-uk 2.126.8. It has no cases, and with `max_examples=0` its sampled properties did not run. The tests use it as an incomplete run, and as the base of a synthetic all-pass report.
+
+The only edit is in `population_pass_max_examples_0.json`: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder. Both files were re-serialized with sorted keys.
diff --git a/tests/fixtures/uk_contract/pinned_uk_2.125.1_defects.json b/tests/fixtures/uk_contract/pinned_uk_2.125.1_defects.json
new file mode 100644
index 00000000..e7d92fa8
--- /dev/null
+++ b/tests/fixtures/uk_contract/pinned_uk_2.125.1_defects.json
@@ -0,0 +1,2050 @@
+{
+ "cases": [
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2027-04-06.2100-12-31'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "detail": "KeyError: 'region'",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2027-04-06.2028-04-05'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "detail": "ValueError: unconverted data remains: .2028-04-05",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 38454.01293702494,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 51275.43382451891,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 246.56476264971067,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 986.0652504709999,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 50.28169156237382,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13077.821120979681,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 52300.8804893913,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 251.49575971156867,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 1005.7853629502536,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 101.599853515625,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 101.56422419593619,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13339.378953034586,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 53346.903736598935,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 256.52570201408514,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 1025.901178621092,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 154.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 153.87579060691715,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13606.152435742164,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "detail": "ValueError('Could not find the parameter gov.economic_assumptions.yoy_growth.september_cpi_uprating (failed at september_cpi_uprating).')",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "error"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "detail": "ValueError('Could not find the parameter gov.economic_assumptions.yoy_growth.september_cpi_uprating (failed at september_cpi_uprating).')",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "error"
+  },
+  {
+   "actual": 3426.0,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3426.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3374.800048828125,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3374.800048828125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3322.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3322.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2031-04-06.2034-04-05'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 38454.01293702494,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 51275.43382451891,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 246.56476264971067,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 986.0652504709999,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 50.28169156237382,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13077.821120979681,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 52300.8804893913,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 251.49575971156867,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 1005.7853629502536,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 101.599853515625,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 101.56422419593619,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13339.378953034586,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 53346.903736598935,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 256.52570201408514,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 1025.901178621092,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 154.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 153.87579060691715,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13606.152435742164,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "detail": "ValueError('Could not find the parameter gov.economic_assumptions.yoy_growth.september_cpi_uprating (failed at september_cpi_uprating).')",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "error"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "detail": "ValueError('Could not find the parameter gov.economic_assumptions.yoy_growth.september_cpi_uprating (failed at september_cpi_uprating).')",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "error"
+  },
+  {
+   "actual": 3426.0,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3426.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3374.800048828125,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3374.800048828125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3322.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3322.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "detail": "ValueError: unconverted data remains: .2034-04-05",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2027-04-06.2028-04-05'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "detail": "ValueError: unconverted data remains: .2028-04-05",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 679.6259765625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2027-04-06.2028-04-05'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 679.6259765625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "detail": "ValueError: unconverted data remains: .2028-04-05",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.18,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2027-10-30.2100-12-31'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 0.18,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 38454.01293702494,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 246.56476264971067,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2030-09-01.2031-08-31'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 12821.408457811869,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 38454.01293702494,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 246.56476264971067,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "detail": "ValueError: Could not find the parameter gov.dwp.universal_credit.rebalancing.protected_health_element (failed at protected_health_element).",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "error"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "detail": "ValueError: Could not find the parameter gov.dwp.universal_credit.rebalancing.protected_health_element (failed at protected_health_element).",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "detail": "ValueError: Could not find the parameter gov.dwp.universal_credit.rebalancing.protected_health_element (failed at protected_health_element).",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "error"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "detail": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.dwp.universal_credit.rebalancing.protected_health_element' (did you mean 'gov.dwp.universal_credit.rebalancing.new_claimant_health_element'?)",
+   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "detail": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.dwp.universal_credit.rebalancing.protected_health_element' (did you mean 'gov.dwp.universal_credit.rebalancing.new_claimant_health_element'?)",
+   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2025-01-01.2030-12-31'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "fail"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "detail": "ValueError: unconverted data remains: .2030-12-31",
+   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+   "route": "wrapper.policy",
+   "status": "error"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "baseline_vat_is_current_law",
+   "check": null,
+   "detail": "ValueError: Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2026-01-01.2100-12-31'.\nLearn more about legal period formats in OpenFisca:\n.",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "error"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "baseline_vat_is_current_law",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "unknown_path",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "fiscal year 2027",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "that year only",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "from 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "onwards",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day is not 30 April",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day only",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": null,
+   "detail": "TypeError: unhashable type: 'dict'",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "error"
+  },
+  {
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": null,
+   "detail": "KeyError: 'region'",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "error"
+  }
+ ],
+ "contract_id": "policyengine-uk/budget-reform-contract",
+ "contract_version": "1.0.0",
+ "dataset": null,
+ "elapsed_seconds": 280.6,
+ "holds": false,
+ "max_examples": 2,
+ "population": [],
+ "prior_law_option": "projected",
+ "properties": [
+  {
+   "detail": "ValueError(\"Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2025-06-01.2100-12-31'.\\nLearn more about legal period formats in OpenFisca:\\n.\")",
+   "engine": "hypothesis",
+   "examples_run": 2,
+   "property_id": "annual_values_match_the_oracle",
+   "status": "error"
+  },
+  {
+   "detail": "ValueError(\"Expected a period (eg. '2017', '2017-01', '2017-01-01', ...); got: '2025-06-01.2100-12-31'.\\nLearn more about legal period formats in OpenFisca:\\n.\")",
+   "engine": "hypothesis",
+   "examples_run": 2,
+   "property_id": "routes_agree_and_baselines_hold",
+   "status": "error"
+  }
+ ],
+ "routes": [
+  "country.reform_dict",
+  "country.scenario_parameter_changes",
+  "country.reform_from_dict",
+  "wrapper.household",
+  "wrapper.policy",
+  "api.sim_api"
+ ],
+ "seed": 0,
+ "summary": {
+  "error": 35,
+  "fail": 66,
+  "pass": 76,
+  "pending": 0,
+  "unsupported": 15
+ },
+ "versions": {
+  "policyengine": "6.2.6",
+  "policyengine-core": "3.33.0",
+  "policyengine-uk": "2.125.1"
+ }
+}
diff --git a/tests/fixtures/uk_contract/population_pass_max_examples_0.json b/tests/fixtures/uk_contract/population_pass_max_examples_0.json
new file mode 100644
index 00000000..22db1db2
--- /dev/null
+++ b/tests/fixtures/uk_contract/population_pass_max_examples_0.json
@@ -0,0 +1,161 @@
+{
+ "cases": [],
+ "contract_id": "policyengine-uk/budget-reform-contract",
+ "contract_version": "1.0.0",
+ "dataset": {
+  "path": "",
+  "sha256": "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
+ },
+ "elapsed_seconds": 23.6,
+ "holds": true,
+ "max_examples": 0,
+ "population": [
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_query_order",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  }
+ ],
+ "prior_law_option": "projected",
+ "properties": [
+  {
+   "examples_run": 0,
+   "property_id": "annual_values_match_the_oracle",
+   "reason": "max_examples is 0, so no examples were requested",
+   "status": "unsupported"
+  },
+  {
+   "examples_run": 0,
+   "property_id": "routes_agree_and_baselines_hold",
+   "reason": "max_examples is 0, so no examples were requested",
+   "status": "unsupported"
+  }
+ ],
+ "routes": [
+  "country.reform_dict",
+  "country.scenario_parameter_changes",
+  "country.reform_from_dict",
+  "wrapper.household",
+  "wrapper.policy",
+  "api.sim_api"
+ ],
+ "seed": 0,
+ "summary": {
+  "error": 0,
+  "fail": 0,
+  "pass": 13,
+  "pending": 0,
+  "unsupported": 2
+ },
+ "versions": {
+  "policyengine": "6.2.6",
+  "policyengine-core": "3.33.0",
+  "policyengine-uk": "2.126.8"
+ }
+}
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 98c84c0d..eb8173fa 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -15,8 +15,10 @@
 from __future__ import annotations
 
 import base64
+import copy
 import hashlib
 import io
+import json
 import zipfile
 from pathlib import Path
 from types import SimpleNamespace
@@ -660,6 +662,142 @@ def test_no_contract_configured_is_unavailable():
     )
 
 
+CONTRACT_FIXTURES = Path(__file__).parent / "fixtures" / "uk_contract"
+CERTIFIED_SHA = "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
+STATUS_RANK = {"pass": 0, "error": 1, "fail": 2}
+
+
+def _fixture(name: str) -> dict:
+    return json.loads((CONTRACT_FIXTURES / name).read_text())
+
+
+def _recount(report: dict) -> dict:
+    """Make a hand-edited report's summary and holds match its rows again."""
+
+    summary = dict.fromkeys(("pass", "fail", "error", "unsupported", "pending"), 0)
+    for section in ("cases", "properties", "population"):
+        for row in report.get(section) or []:
+            summary[row["status"]] += 1
+    report["summary"] = summary
+    report["holds"] = summary["fail"] == 0 and summary["error"] == 0
+    return report
+
+
+def _passing_report() -> dict:
+    """W1's population run, with its cases and properties all passing."""
+
+    report = _fixture("population_pass_max_examples_0.json")
+    defects = _fixture("pinned_uk_2.125.1_defects.json")
+    report["cases"] = [
+        {**case, "status": "pass"}
+        for case in defects["cases"]
+        if case["status"] in ("pass", "fail", "error")
+    ]
+    report["properties"] = [
+        {"property_id": row["property_id"], "status": "pass", "examples_run": 20}
+        for row in report["properties"]
+    ]
+    report["max_examples"] = 20
+    return _recount(report)
+
+
+def _run_contract(report, *, versions=None, dataset_sha=CERTIFIED_SHA, **kwargs):
+    kwargs.setdefault("seed", 0)
+    kwargs.setdefault("max_examples", 20)
+    kwargs.setdefault("dataset_path", Path("enhanced_frs_2024_25.h5"))
+    return reform_contract(
+        entrypoint=ENTRY,
+        importer=_importer(report=report),
+        expected_versions=versions
+        or {"policyengine-uk": "2.126.8", "policyengine-core": "3.33.0"},
+        expected_dataset_sha256=dataset_sha,
+        **kwargs,
+    )[0]
+
+
+def test_w1_report_on_the_pinned_model_fails_on_its_defects():
+    """W1's real report on policyengine-uk 2.125.1: 66 failures and 35 errors."""
+
+    report = _fixture("pinned_uk_2.125.1_defects.json")
+    result = _run_contract(
+        report,
+        versions={"policyengine-uk": "2.125.1", "policyengine-core": "3.33.0"},
+        dataset_sha=None,
+        dataset_path=None,
+        max_examples=report["max_examples"],
+    )
+    assert result.status == "fail"
+    assert result.summary.startswith("101 contract row(s) failed")
+    assert result.details["problems"] == []
+
+
+def test_w1_population_run_alone_is_incomplete():
+    """W1's real population-only run has no cases and no sampled properties."""
+
+    result = _run_contract(
+        _fixture("population_pass_max_examples_0.json"), max_examples=0
+    )
+    assert result.status == "error"
+    problems = result.details["problems"]
+    assert "the report has no cases" in problems
+    assert any("annual_values_match_the_oracle did not run" in p for p in problems)
+
+
+def test_a_full_passing_report_passes():
+    result = _run_contract(_passing_report())
+    assert result.status == "pass", result.summary
+    assert "every case, property and population check passed" in result.summary
+
+
+REPORT_TAMPERING = {
+    "other model": lambda r: r["versions"].update({"policyengine-uk": "2.125.1"}),
+    "other core": lambda r: r["versions"].update({"policyengine-core": "3.30.0"}),
+    "other dataset": lambda r: r["dataset"].update(sha256="0" * 64),
+    "no population": lambda r: _recount({**r, "population": []}),
+    "other seed": lambda r: r.update(seed=7),
+    "fewer examples": lambda r: r.update(max_examples=5),
+    "summary": lambda r: r["summary"].update(
+        unsupported=r["summary"]["unsupported"] + 1
+    ),
+    "holds": lambda r: r.update(holds=False),
+    "pending without decision": lambda r: _recount(
+        {**r, "cases": [{**r["cases"][0], "status": "pending"}, *r["cases"][1:]]}
+    ),
+    "unsupported without reason": lambda r: _recount(
+        {
+            **r,
+            "population": [
+                {**r["population"][0], "status": "unsupported"},
+                *r["population"][1:],
+            ],
+        }
+    ),
+}
+
+
+@pytest.mark.parametrize("name", sorted(REPORT_TAMPERING))
+def test_a_report_that_is_not_a_full_run_of_this_candidate_is_an_error(name):
+    report = copy.deepcopy(_passing_report())
+    tampered = REPORT_TAMPERING[name](report) or report
+    assert _run_contract(tampered).status == "error"
+
+
+@settings(max_examples=40, deadline=None)
+@given(
+    data=st.data(),
+    worse=st.sampled_from(["fail", "error"]),
+    section=st.sampled_from(["cases", "properties", "population"]),
+)
+def test_a_worse_row_never_improves_the_gate(data, worse, section):
+    """Monotone: turning any row into a failure fails the gate."""
+
+    report = _passing_report()
+    index = data.draw(st.integers(0, len(report[section]) - 1))
+    report[section][index] = {**report[section][index], "status": worse}
+    result = _run_contract(_recount(report))
+    assert STATUS_RANK[result.status] >= STATUS_RANK["fail"]
+
+
 # --- Metrics review ------------------------------------------------------------------
 
 BOUNDS = {

From da267e221031f325fdb128be4dd812fcb89a94bb Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 17:31:53 -0400
Subject: [PATCH 07/45] Test the contract gate on W1's real full all-pass
 report

Replaces the synthetic all-pass report with W1's full run (every route,
20 examples, the certified dataset): 267 pass, 6 pending d1344, 67
unsupported with reasons, both properties and 13/13 population checks.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 tests/fixtures/uk_contract/README.md          |    5 +-
 .../uk_contract/full_allpass_uk_2.126.8.json  | 3665 +++++++++++++++++
 tests/test_uk_candidate_gates.py              |   26 +-
 3 files changed, 3677 insertions(+), 19 deletions(-)
 create mode 100644 tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json

diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index 94ee01dd..e6d4e87f 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -5,6 +5,7 @@ Real reports from the UK Budget reform contract runner (workstream W1,
 run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate_gates.py` read them.
 
 - `pinned_uk_2.125.1_defects.json`: every case on policyengine-uk 2.125.1, the pinned model at the time, with `max_examples=2` and no dataset. The 66 failures and 35 errors are the dated-reform defects the contract was written to catch.
-- `population_pass_max_examples_0.json`: population checks only, on a 1,000-household subsample of the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`), policyengine-uk 2.126.8. It has no cases, and with `max_examples=0` its sampled properties did not run. The tests use it as an incomplete run, and as the base of a synthetic all-pass report.
+- `full_allpass_uk_2.126.8.json`: the full run the gate expects. Every route and case, seed 0, `max_examples=20`, and population checks on the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`). The model was policyengine-uk 2.126.8 from the policyengine-uk#2305 branch with core 3.33.0, a development combination rather than a certified pair, so treat its `versions` as fixture metadata. Result: 267 pass, 6 pending decision d1344, 67 unsupported with reasons, both properties passing, 13 of 13 population checks; 20.6 minutes, peak RSS 2.7 GB.
+- `population_pass_max_examples_0.json`: population checks only, on the same dataset. It has no cases, and with `max_examples=0` its sampled properties did not run, so the gate treats it as an incomplete run.
 
-The only edit is in `population_pass_max_examples_0.json`: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder. Both files were re-serialized with sorted keys.
+The only edits: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
diff --git a/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json b/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json
new file mode 100644
index 00000000..4c3feeb6
--- /dev/null
+++ b/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json
@@ -0,0 +1,3665 @@
+{
+ "cases": [
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "unknown_path",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "fiscal year 2027",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "that year only",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "from 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "onwards",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day is not 30 April",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day only",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  }
+ ],
+ "contract_id": "policyengine-uk/budget-reform-contract",
+ "contract_version": "1.0.0",
+ "dataset": {
+  "path": "",
+  "sha256": "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
+ },
+ "elapsed_seconds": 1234.3,
+ "holds": true,
+ "max_examples": 20,
+ "population": [
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_query_order",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0
+   },
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  }
+ ],
+ "prior_law_option": "projected",
+ "properties": [
+  {
+   "engine": "hypothesis",
+   "examples_run": 20,
+   "property_id": "annual_values_match_the_oracle",
+   "status": "pass"
+  },
+  {
+   "engine": "hypothesis",
+   "examples_run": 20,
+   "property_id": "routes_agree_and_baselines_hold",
+   "status": "pass"
+  }
+ ],
+ "routes": [
+  "country.reform_dict",
+  "country.scenario_parameter_changes",
+  "country.reform_from_dict",
+  "wrapper.household",
+  "wrapper.policy",
+  "api.sim_api"
+ ],
+ "seed": 0,
+ "summary": {
+  "error": 0,
+  "fail": 0,
+  "pass": 267,
+  "pending": 6,
+  "unsupported": 67
+ },
+ "versions": {
+  "policyengine": "6.2.6",
+  "policyengine-core": "3.33.0",
+  "policyengine-uk": "2.126.8"
+ }
+}
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index eb8173fa..bba782a6 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -684,21 +684,9 @@ def _recount(report: dict) -> dict:
 
 
 def _passing_report() -> dict:
-    """W1's population run, with its cases and properties all passing."""
-
-    report = _fixture("population_pass_max_examples_0.json")
-    defects = _fixture("pinned_uk_2.125.1_defects.json")
-    report["cases"] = [
-        {**case, "status": "pass"}
-        for case in defects["cases"]
-        if case["status"] in ("pass", "fail", "error")
-    ]
-    report["properties"] = [
-        {"property_id": row["property_id"], "status": "pass", "examples_run": 20}
-        for row in report["properties"]
-    ]
-    report["max_examples"] = 20
-    return _recount(report)
+    """W1's real full run: every route, 20 examples, the certified dataset."""
+
+    return _fixture("full_allpass_uk_2.126.8.json")
 
 
 def _run_contract(report, *, versions=None, dataset_sha=CERTIFIED_SHA, **kwargs):
@@ -743,10 +731,14 @@ def test_w1_population_run_alone_is_incomplete():
     assert any("annual_values_match_the_oracle did not run" in p for p in problems)
 
 
-def test_a_full_passing_report_passes():
+def test_w1_full_run_passes():
+    """W1's real all-pass report: 267 pass, 6 pending d1344, 67 unsupported."""
+
     result = _run_contract(_passing_report())
     assert result.status == "pass", result.summary
-    assert "every case, property and population check passed" in result.summary
+    assert "every case, property and population check passed (267)" in result.summary
+    assert "6 pending a methodology call" in result.summary
+    assert result.details["problems"] == []
 
 
 REPORT_TAMPERING = {

From def8b8d9744864e8608b2ff199f5fb7e05ffaa04 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 17:59:11 -0400
Subject: [PATCH 08/45] Follow the scorecard's tightened replay interface
 (dc040de)

- Re-vendor the replay schemas and golden fixtures at scorecard dc040de:
  the golden receipt gains results.manifest_sha256.
- ReplayReceipt mirror: a rejected receipt has no variant, identity or
  execution and integrity not_run; a complete receipt has its variant
  identity and a sealed results manifest; execution.python is anchored.
  The request mirror refuses '..' path segments. Differential tests check
  the mirror and the schemas reject the same documents.
- expected_release_bundle runs in the scorecard's certification
  environment (no tokens, no proxy exceptions, proxies to 127.0.0.1:9),
  so packaged certification is used for a private or public data repo; a
  test executes the manifest fetch under it and sees it fail over.
- The release dispatch carries the receipt's promotable flag.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 .../vendor/policyengine-scorecard/README.md   |  2 +-
 .../qualification_request.v1.json             |  4 +-
 .../replay_receipt.v1.json                    | 26 ++++-
 src/policyengine/provenance/qualification.py  | 25 ++++-
 .../provenance/uk_qualification.py            | 52 +++++++++-
 tests/fixtures/uk_replay/DIGESTS.json         |  2 +-
 tests/fixtures/uk_replay/README.md            |  2 +-
 .../uk_replay/replay_receipt_golden.jcs       |  2 +-
 .../uk_replay/replay_receipt_golden.json      |  5 +-
 tests/test_qualification_contracts.py         | 97 +++++++++++++++++++
 tests/test_uk_qualification_pipeline.py       | 69 +++++++++++++
 11 files changed, 269 insertions(+), 17 deletions(-)

diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
index e3fe467b..b8a52769 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/README.md
@@ -1,7 +1,7 @@
 # Vendored policyengine-scorecard schemas
 
 Copied unchanged from PolicyEngine/policyengine-scorecard, branch
-`w6/replay-variants`, commit `91f46c1` (`docs/uk_replay/schemas/`): the v1
+`w6/replay-variants`, commit `dc040de` (`docs/uk_replay/schemas/`): the v1
 pre-promotion replay interface between policyengine.py qualification (W4)
 and the replay corpus (W6). `policyengine.provenance.qualification` mirrors
 them, and `tests/test_qualification_contracts.py` checks the mirrors and the
diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
index 16921af5..5865ca3e 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/qualification_request.v1.json
@@ -76,14 +76,14 @@
       "repo_id": {"type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$"},
       "repo_type": {"enum": ["model", "dataset"]},
       "revision": {"type": "string", "minLength": 1},
-      "path": {"type": "string", "minLength": 1, "pattern": "^[^/][^\\\\]*$"},
+      "path": {"type": "string", "minLength": 1, "pattern": "^(?!.*(^|/)\\.\\.(/|$))[^/][^\\\\]*$"},
       "sha256": {"$ref": "#/$defs/sha256"},
       "size_bytes": {"type": "integer", "minimum": 1},
       "release_manifest_sha256": {"$ref": "#/$defs/sha256"}
      }
     },
     "expected_release_bundle": {
-     "description": "The exact dict(pe.uk.uk_latest.release_bundle) under packaged certification, computed with HF_TOKEN, HUGGING_FACE_TOKEN and HUGGINGFACE_HUB_TOKEN removed from the environment.",
+     "description": "The exact dict(pe.uk.uk_latest.release_bundle) under packaged certification: computed in a subprocess with HF_TOKEN, HUGGING_FACE_TOKEN, HUGGINGFACE_HUB_TOKEN, NO_PROXY and no_proxy removed and HTTP_PROXY, HTTPS_PROXY, ALL_PROXY (and their lowercase forms) set to http://127.0.0.1:9, so the wrapper's release-manifest request cannot reach the network and the packaged certification is used for a private or public data repository (pipeline/uk_replay_variants.py, isolate_certification_environment).",
      "type": "object",
      "required": ["policyengine_version", "model_version", "certified_data_build_id", "certified_data_artifact_sha256", "default_dataset_uri"],
      "additionalProperties": {"type": ["string", "null"]},
diff --git a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
index f127f28a..a9d52614 100644
--- a/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
+++ b/src/policyengine/data/schemas/vendor/policyengine-scorecard/replay_receipt.v1.json
@@ -140,7 +140,7 @@
       },
       "python": {
        "type": "string",
-       "pattern": "^3\\.[0-9]+\\.[0-9]+"
+       "pattern": "^3\\.[0-9]+\\.[0-9]+$"
       },
       "platform": {
        "type": "string",
@@ -421,6 +421,22 @@
      },
      "diff": {
       "type": "null"
+     },
+     "variant_id": {
+      "type": "null"
+     },
+     "variant_identity_sha256": {
+      "type": "null"
+     },
+     "execution": {
+      "type": "null"
+     },
+     "integrity": {
+      "properties": {
+       "status": {
+        "const": "not_run"
+       }
+      }
      }
     }
    }
@@ -443,6 +459,14 @@
      },
      "execution": {
       "type": "object"
+     },
+     "variant_identity_sha256": {
+      "$ref": "#/$defs/sha256"
+     },
+     "results": {
+      "required": [
+       "manifest_sha256"
+      ]
      }
     }
    }
diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index 141b35b0..41752c66 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -413,6 +413,15 @@ class RequestData(_Mirror):
     size_bytes: int = Field(ge=1)
     release_manifest_sha256: str = Field(pattern=SHA256_PATTERN)
 
+    @field_validator("path")
+    @classmethod
+    def _no_parent_segments(cls, path: str) -> str:
+        # The schema says ^(?!.*(^|/)\.\.(/|$))[^/][^\\]*$; pydantic's regex
+        # engine has no look-ahead, so the '..' rule is checked here.
+        if ".." in path.split("/"):
+            raise ValueError("data.path must not contain '..' segments.")
+        return path
+
 
 class RequestCandidate(_Mirror):
     policyengine: RequestWrapper
@@ -534,7 +543,7 @@ class Execution(_Mirror):
     release_bundle: dict[str, Optional[str]]
     dataset_sha256: str = Field(pattern=SHA256_PATTERN)
     requirements_sha256: str = Field(pattern=SHA256_PATTERN)
-    python: str = Field(pattern=r"^3\.[0-9]+\.[0-9]+")
+    python: str = Field(pattern=r"^3\.[0-9]+\.[0-9]+$")
     platform: str = Field(min_length=1)
     runner: str = Field(min_length=1)
 
@@ -686,17 +695,27 @@ def _status_shape(self) -> ReplayReceipt:
                 self.rejection is None
                 or self.corpus is not None
                 or self.diff is not None
+                or self.variant_id is not None
+                or self.variant_identity_sha256 is not None
+                or self.execution is not None
+                or self.integrity.status != "not_run"
             ):
                 raise ValueError(
-                    "A rejected receipt has a rejection and no corpus or diff."
+                    "A rejected receipt has a rejection, no variant, execution, "
+                    "corpus or diff, and integrity not_run."
                 )
         elif self.status == "complete":
             if (
                 self.rejection is not None
                 or self.variant_id is None
+                or self.variant_identity_sha256 is None
                 or self.execution is None
+                or self.results.manifest_sha256 is None
             ):
-                raise ValueError("A complete receipt has a variant and an execution.")
+                raise ValueError(
+                    "A complete receipt has a variant and its identity, an "
+                    "execution and a sealed results manifest."
+                )
         # A failed receipt can come from a step before the candidate's
         # identity was known (for example a download error).
         elif self.rejection is not None or self.integrity.status != "failed":
diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index a8261556..8e139728 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -82,6 +82,46 @@
 UK_DATA_REPO_ID = "policyengine/policyengine-uk-data-private"
 UK_DATA_REPO_TYPE: Literal["model"] = "model"
 TOKEN_VARIABLES = ("HF_TOKEN", "HUGGING_FACE_TOKEN", "HUGGINGFACE_HUB_TOKEN")
+#: The scorecard's certification recipe (policyengine-scorecard
+#: pipeline/uk_replay_variants.py, isolate_certification_environment), which
+#: expected_release_bundle must reproduce exactly. policyengine.py 6.x fetches
+#: the data release manifest with requests, which ignores HF_HUB_OFFLINE; with
+#: these proxies the fetch fails at once for a private or public data repo and
+#: certify_data_release_compatibility falls back to the packaged certification.
+PROXY_EXCEPTIONS = ("NO_PROXY", "no_proxy")
+OFFLINE_VARIABLES = {
+    "HF_HUB_OFFLINE": "1",
+    "HF_DATASETS_OFFLINE": "1",
+    "TRANSFORMERS_OFFLINE": "1",
+    "HF_HUB_DISABLE_TELEMETRY": "1",
+    "HF_HUB_DISABLE_IMPLICIT_TOKEN": "1",
+}
+NO_NETWORK = {
+    name: "http://127.0.0.1:9"
+    for name in (
+        "HTTP_PROXY",
+        "HTTPS_PROXY",
+        "ALL_PROXY",
+        "http_proxy",
+        "https_proxy",
+        "all_proxy",
+    )
+}
+
+
+def certification_environment(environ: Mapping[str, str]) -> dict[str, str]:
+    """``environ`` as the scorecard isolates it before reading release_bundle."""
+
+    env = {
+        key: value
+        for key, value in environ.items()
+        if key not in TOKEN_VARIABLES and key not in PROXY_EXCEPTIONS
+    }
+    env.update(OFFLINE_VARIABLES)
+    env.update(NO_NETWORK)
+    return env
+
+
 REPO_ROOT = Path(__file__).resolve().parents[3]
 
 Action = Literal["qualify", "already_certified", "stale", "duplicate"]
@@ -533,13 +573,12 @@ def packaged_manifest_sha256(repo_root: Path) -> str:
 def expected_release_bundle(python: str, *, cwd: Path) -> dict[str, Optional[str]]:
     """``dict(pe.uk.uk_latest.release_bundle)`` under packaged certification.
 
-    Runs in a subprocess with every Hugging Face token removed, as the
-    scorecard does, so the bundled certification is what is reported.
+    Runs in a subprocess in the scorecard's certification environment (no
+    tokens, no network for the release-manifest request), so the bundled
+    certification is what is reported for a private or public data repo.
     """
 
-    env = {
-        key: value for key, value in os.environ.items() if key not in TOKEN_VARIABLES
-    }
+    env = certification_environment(os.environ)
     output = subprocess.run(
         [
             python,
@@ -982,6 +1021,9 @@ def release_dispatch_payload(
             "uk": {
                 "pair_id": pair_id,
                 "verdict": receipt.verdict if receipt is not None else None,
+                # needs_review pairs are promotable only with an acceptance of
+                # exactly that receipt; consumers refuse promotable=false.
+                "promotable": receipt.promotable if receipt is not None else None,
                 "receipt_sha256": receipt.receipt_sha256
                 if receipt is not None
                 else None,
diff --git a/tests/fixtures/uk_replay/DIGESTS.json b/tests/fixtures/uk_replay/DIGESTS.json
index b7e61f62..c7f000d9 100644
--- a/tests/fixtures/uk_replay/DIGESTS.json
+++ b/tests/fixtures/uk_replay/DIGESTS.json
@@ -3,6 +3,6 @@
   "request_id": "2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf"
  },
  "replay_receipt_golden.json": {
-  "receipt_sha256": "a070ac40cb4e6d7daef520cfc1be4ed4958cdd4fe275975dc6d55e856d4ff515"
+  "receipt_sha256": "5cbc44c1b79506a6410c12b437a7451a0e1387ab6a133b9cb8dc0bf71b396650"
  }
 }
diff --git a/tests/fixtures/uk_replay/README.md b/tests/fixtures/uk_replay/README.md
index 98c80f60..398abb5c 100644
--- a/tests/fixtures/uk_replay/README.md
+++ b/tests/fixtures/uk_replay/README.md
@@ -1,7 +1,7 @@
 # UK replay interface golden fixtures
 
 Vendored unchanged from PolicyEngine/policyengine-scorecard at commit
-`7cfa3f9` (`tests/fixtures/uk_replay/`), the W6 side of the pre-promotion
+`dc040de` (`tests/fixtures/uk_replay/`), the W6 side of the pre-promotion
 replay interface. The scorecard computes digests with `rfc8785==0.1.4`;
 `tests/test_canonical_json.py` checks that
 `policyengine.provenance.canonical` produces the same bytes and digests.
diff --git a/tests/fixtures/uk_replay/replay_receipt_golden.jcs b/tests/fixtures/uk_replay/replay_receipt_golden.jcs
index 871f1d32..d542e5bd 100644
--- a/tests/fixtures/uk_replay/replay_receipt_golden.jcs
+++ b/tests/fixtures/uk_replay/replay_receipt_golden.jcs
@@ -1 +1 @@
-{"corpus":{"corpus_version":"uk-fiscal-event-replay/1","events":{"spring_budget_2023":{"artifacts":8,"comparison_provenance_sha256":"8888888888888888888888888888888888888888888888888888888888888888","full_supported_grid_complete":true,"inert_measure_years":[],"registry_sha256":"5555555555555555555555555555555555555555555555555555555555555555","run_manifest_sha256":"6666666666666666666666666666666666666666666666666666666666666666","staging_manifest_sha256":"7777777777777777777777777777777777777777777777777777777777777777","supported_years":[2024,2025,2026,2027],"unsupported_years":[{"reason":"before_data_year","year":2023}]}}},"diff":{"base_variant_id":"pe5.0.2_uk2.89.2_populace-uk-2023-dd68c73-4aa4b14-20260619T023711Z","diff_sha256":"9999999999999999999999999999999999999999999999999999999999999999","flag_counts":{"construction":0,"coverage":0,"inertness":0,"mapping":0,"numerical":2,"structural":1,"support":1},"flagged_rows":[{"base_gbp":-15000000000000000,"event":"spring_budget_2023","flags":["numerical"],"head_gbp":0.30000000000000004,"key":"universal_credit","level":"head","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2024},{"base_gbp":1e-7,"event":"spring_budget_2023","flags":["numerical","structural"],"head_gbp":-123456789.125,"key":"total","level":"measure_year","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2025},{"base_gbp":-2500000,"event":"spring_budget_2023","flags":["support"],"head_gbp":null,"key":"obr-pmd-row-123","level":"source_row","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2023}]},"execution":{"dataset_sha256":"5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6","packaged_bundle_manifest_sha256":"8633ad814c9c85e53c7c513f69c4c7b1500a03cd2f6ef133d6e2ea8346b2db54","packages":{"policyengine":{"record_sha256":"1111111111111111111111111111111111111111111111111111111111111111","version":"6.2.6"},"policyengine-core":{"record_sha256":"3333333333333333333333333333333333333333333333333333333333333333","version":"3.33.0"},"policyengine-uk":{"record_sha256":"2222222222222222222222222222222222222222222222222222222222222222","version":"2.125.1"}},"platform":"Golden fixture (synthetic values; café £)","python":"3.12.14","release_bundle":{"bundle_id":"uk-6.2.6","certified_by":"policyengine.py bundle certification","certified_data_artifact_sha256":"5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6","certified_data_build_id":"policyengine-uk-data-1.58.0","compatibility_basis":"legacy_compatible_model_package","country_id":"uk","data_build_fingerprint":"sha256:c094d7006fdd81df220090284212f16bbffb15624643bc442c4bb3e1b1e5dac8","data_build_model_git_sha":"4cbedbecca352f52dffe47e849553c2759a00711","data_build_model_version":"2.122.2","data_package":"policyengine-uk-data","data_version":"1.58.0","default_dataset":"enhanced_frs_2024_25","default_dataset_uri":"hf://policyengine/policyengine-uk-data-private/enhanced_frs_2024_25.h5@1.58.0","model_package":"policyengine-uk","model_version":"2.125.1","policyengine_version":"6.2.6"},"requirements_sha256":"4444444444444444444444444444444444444444444444444444444444444444","runner":"github-actions ubuntu-latest"},"integrity":{"failures":[],"status":"complete"},"rejection":null,"request_id":"2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf","results":{"commit":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","path":"requests/2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf/results/","ref":"replay-state","repository":"PolicyEngine/policyengine-scorecard"},"schema":"policyengine.uk-replay-receipt/v1","status":"complete","variant_id":"pe6.2.6_uk2.125.1_policyengine-uk-data-1.58.0","variant_identity_sha256":"0000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
+{"corpus":{"corpus_version":"uk-fiscal-event-replay/1","events":{"spring_budget_2023":{"artifacts":8,"comparison_provenance_sha256":"8888888888888888888888888888888888888888888888888888888888888888","full_supported_grid_complete":true,"inert_measure_years":[],"registry_sha256":"5555555555555555555555555555555555555555555555555555555555555555","run_manifest_sha256":"6666666666666666666666666666666666666666666666666666666666666666","staging_manifest_sha256":"7777777777777777777777777777777777777777777777777777777777777777","supported_years":[2024,2025,2026,2027],"unsupported_years":[{"reason":"before_data_year","year":2023}]}}},"diff":{"base_variant_id":"pe5.0.2_uk2.89.2_populace-uk-2023-dd68c73-4aa4b14-20260619T023711Z","diff_sha256":"9999999999999999999999999999999999999999999999999999999999999999","flag_counts":{"construction":0,"coverage":0,"inertness":0,"mapping":0,"numerical":2,"structural":1,"support":1},"flagged_rows":[{"base_gbp":-15000000000000000,"event":"spring_budget_2023","flags":["numerical"],"head_gbp":0.30000000000000004,"key":"universal_credit","level":"head","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2024},{"base_gbp":1e-7,"event":"spring_budget_2023","flags":["numerical","structural"],"head_gbp":-123456789.125,"key":"total","level":"measure_year","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2025},{"base_gbp":-2500000,"event":"spring_budget_2023","flags":["support"],"head_gbp":null,"key":"obr-pmd-row-123","level":"source_row","measure_key":"spring_budget_2023__uc_childcare_cap_increase","year":2023}]},"execution":{"dataset_sha256":"5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6","packaged_bundle_manifest_sha256":"8633ad814c9c85e53c7c513f69c4c7b1500a03cd2f6ef133d6e2ea8346b2db54","packages":{"policyengine":{"record_sha256":"1111111111111111111111111111111111111111111111111111111111111111","version":"6.2.6"},"policyengine-core":{"record_sha256":"3333333333333333333333333333333333333333333333333333333333333333","version":"3.33.0"},"policyengine-uk":{"record_sha256":"2222222222222222222222222222222222222222222222222222222222222222","version":"2.125.1"}},"platform":"Golden fixture (synthetic values; café £)","python":"3.12.14","release_bundle":{"bundle_id":"uk-6.2.6","certified_by":"policyengine.py bundle certification","certified_data_artifact_sha256":"5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6","certified_data_build_id":"policyengine-uk-data-1.58.0","compatibility_basis":"legacy_compatible_model_package","country_id":"uk","data_build_fingerprint":"sha256:c094d7006fdd81df220090284212f16bbffb15624643bc442c4bb3e1b1e5dac8","data_build_model_git_sha":"4cbedbecca352f52dffe47e849553c2759a00711","data_build_model_version":"2.122.2","data_package":"policyengine-uk-data","data_version":"1.58.0","default_dataset":"enhanced_frs_2024_25","default_dataset_uri":"hf://policyengine/policyengine-uk-data-private/enhanced_frs_2024_25.h5@1.58.0","model_package":"policyengine-uk","model_version":"2.125.1","policyengine_version":"6.2.6"},"requirements_sha256":"4444444444444444444444444444444444444444444444444444444444444444","runner":"github-actions ubuntu-latest"},"integrity":{"failures":[],"status":"complete"},"rejection":null,"request_id":"2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf","results":{"commit":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","manifest_sha256":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","path":"requests/2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf/results/","ref":"replay-state","repository":"PolicyEngine/policyengine-scorecard"},"schema":"policyengine.uk-replay-receipt/v1","status":"complete","variant_id":"pe6.2.6_uk2.125.1_policyengine-uk-data-1.58.0","variant_identity_sha256":"0000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
diff --git a/tests/fixtures/uk_replay/replay_receipt_golden.json b/tests/fixtures/uk_replay/replay_receipt_golden.json
index 433f095c..87898936 100644
--- a/tests/fixtures/uk_replay/replay_receipt_golden.json
+++ b/tests/fixtures/uk_replay/replay_receipt_golden.json
@@ -131,7 +131,8 @@
   "repository": "PolicyEngine/policyengine-scorecard",
   "ref": "replay-state",
   "commit": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
-  "path": "requests/2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf/results/"
+  "path": "requests/2e4dd8350bfdc5a39780e002c14ab49c02cbf28b77b222af420e38c68bb945cf/results/",
+  "manifest_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  },
- "receipt_sha256": "a070ac40cb4e6d7daef520cfc1be4ed4958cdd4fe275975dc6d55e856d4ff515"
+ "receipt_sha256": "5cbc44c1b79506a6410c12b437a7451a0e1387ab6a133b9cb8dc0bf71b396650"
 }
diff --git a/tests/test_qualification_contracts.py b/tests/test_qualification_contracts.py
index f46ae768..bc54bdf2 100644
--- a/tests/test_qualification_contracts.py
+++ b/tests/test_qualification_contracts.py
@@ -301,6 +301,100 @@ def test_request_mirror_and_schema_reject_the_same_requests(label, mutate):
         ReplayQualificationRequest.model_validate(raw)
 
 
+REQUEST_MUTATIONS_V1_TIGHTENED = [
+    ("parent segment", "../enhanced_frs_2024_25.h5"),
+    ("nested parent", "a/../b.h5"),
+    ("trailing parent", "a/.."),
+]
+
+
+@pytest.mark.parametrize(
+    ("label", "path"),
+    REQUEST_MUTATIONS_V1_TIGHTENED,
+    ids=[m[0] for m in REQUEST_MUTATIONS_V1_TIGHTENED],
+)
+def test_request_mirror_and_schema_refuse_parent_segments(label, path):
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["candidate"]["data"]["path"] = path
+    assert not _validator("qualification_request.v1.json").is_valid(raw), label
+    with pytest.raises(ValidationError):
+        ReplayQualificationRequest.model_validate(raw)
+
+
+def test_request_mirror_and_schema_accept_dotted_names():
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["candidate"]["data"]["path"] = "releases/1.58.0/..hidden.h5"
+    _validator("qualification_request.v1.json").validate(raw)
+    ReplayQualificationRequest.model_validate(raw)
+
+
+def _rejected_receipt():
+    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    doc.update(
+        status="rejected",
+        rejection={"code": "artifact_hash_mismatch", "detail": "dataset bytes differ"},
+        corpus=None,
+        diff=None,
+        variant_id=None,
+        variant_identity_sha256=None,
+        execution=None,
+    )
+    doc["integrity"] = {"status": "not_run", "failures": []}
+    return _sealed(doc)
+
+
+RECEIPT_MUTATIONS = [
+    (
+        "complete without manifest",
+        "complete",
+        lambda r: r["results"].pop("manifest_sha256"),
+    ),
+    (
+        "complete without identity",
+        "complete",
+        lambda r: r.update(variant_identity_sha256=None),
+    ),
+    (
+        "unanchored python",
+        "complete",
+        lambda r: r["execution"].update(python="3.12.14+local"),
+    ),
+    ("rejected with variant", "rejected", lambda r: r.update(variant_id="pe6.2.6")),
+    (
+        "rejected with identity",
+        "rejected",
+        lambda r: r.update(variant_identity_sha256="0" * 64),
+    ),
+    (
+        "rejected with integrity",
+        "rejected",
+        lambda r: r.update(integrity={"status": "failed", "failures": []}),
+    ),
+]
+
+
+@pytest.mark.parametrize(
+    ("label", "base", "mutate"),
+    RECEIPT_MUTATIONS,
+    ids=[m[0] for m in RECEIPT_MUTATIONS],
+)
+def test_receipt_mirror_and_schema_reject_the_same_receipts(label, base, mutate):
+    """Differential against W6's tightened replay_receipt.v1.json (dc040de)."""
+
+    raw = (
+        copy.deepcopy(golden("replay_receipt_golden"))
+        if base == "complete"
+        else _rejected_receipt()
+    )
+    _validator("replay_receipt.v1.json").validate(raw)
+    ReplayReceipt.from_document(raw)
+    mutate(raw)
+    raw = _sealed(raw)
+    assert not _validator("replay_receipt.v1.json").is_valid(raw), label
+    with pytest.raises(ValidationError):
+        ReplayReceipt.from_document(raw)
+
+
 def test_requested_by_is_open_as_in_the_schema():
     raw = copy.deepcopy(golden("qualification_request_golden"))
     raw["requested_by"]["pair_id"] = sha("a")
@@ -422,6 +516,9 @@ def test_rejected_receipt_fails_with_its_code():
         rejection={"code": "artifact_hash_mismatch", "detail": "dataset bytes differ"},
         corpus=None,
         diff=None,
+        variant_id=None,
+        variant_identity_sha256=None,
+        execution=None,
     )
     doc["integrity"] = {"status": "not_run", "failures": []}
     gate = _gate(_sealed(doc))
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index 1964fcf4..ee24ac87 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -509,6 +509,7 @@ def test_release_payload_names_the_qualification_receipt():
         "uk": {
             "pair_id": receipt.pair_id,
             "verdict": "qualified",
+            "promotable": True,
             "receipt_sha256": receipt.receipt_sha256,
         }
     }
@@ -564,3 +565,71 @@ def test_released_bundle_request_is_valid_for_the_scorecard():
     assert request.document()["candidate"]["policyengine"]["source"] == {
         "pypi": {"wheel_sha256": sha("7")}
     }
+
+
+def test_expected_release_bundle_uses_the_scorecard_certification_environment(
+    monkeypatch, tmp_path
+):
+    """W6 interface point 4: no tokens, no proxy exceptions, no network."""
+
+    from policyengine.provenance import uk_qualification
+
+    environ = {
+        "PATH": "/usr/bin",
+        "HF_TOKEN": "t",
+        "HUGGING_FACE_TOKEN": "t",
+        "HUGGINGFACE_HUB_TOKEN": "t",
+        "NO_PROXY": "huggingface.co",
+        "no_proxy": "huggingface.co",
+        "HTTPS_PROXY": "http://corporate:3128",
+    }
+    env = uk_qualification.certification_environment(environ)
+    assert env["PATH"] == "/usr/bin"
+    for name in ("HF_TOKEN", "HUGGING_FACE_TOKEN", "HUGGINGFACE_HUB_TOKEN"):
+        assert name not in env
+    assert "NO_PROXY" not in env and "no_proxy" not in env
+    for name in ("HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY"):
+        assert env[name] == env[name.lower()] == "http://127.0.0.1:9"
+    assert env["HF_HUB_OFFLINE"] == "1"
+
+    seen = {}
+
+    def run(args, *, cwd, env, check, capture_output, text):
+        seen["env"] = env
+        return type("Done", (), {"stdout": '{"policyengine_version": "6.2.6"}\n'})()
+
+    monkeypatch.setattr(uk_qualification.subprocess, "run", run)
+    monkeypatch.setattr(uk_qualification.os, "environ", environ)
+    assert uk_qualification.expected_release_bundle("python", cwd=tmp_path) == {
+        "policyengine_version": "6.2.6"
+    }
+    assert seen["env"] == env
+
+
+def test_the_certification_environment_falls_back_to_the_packaged_certificate():
+    """Executed: with the proxies, the manifest request fails and the bundled
+    certification is used (the mechanism W6's recipe relies on)."""
+
+    import os
+    import subprocess
+    import sys
+
+    from policyengine.provenance import uk_qualification
+
+    script = (
+        "import json\n"
+        "from policyengine.provenance import manifest\n"
+        "try:\n"
+        "    manifest.get_data_release_manifest('uk')\n"
+        "    print('reached')\n"
+        "except manifest.DataReleaseManifestUnavailableError:\n"
+        "    print('unavailable')\n"
+    )
+    result = subprocess.run(
+        [sys.executable, "-c", script],
+        env=uk_qualification.certification_environment(os.environ),
+        capture_output=True,
+        text=True,
+        timeout=60,
+    )
+    assert result.stdout.strip().splitlines()[-1] == "unavailable", result.stderr

From 28c90eabdcb5695e5ecb97811495e68de2f706fb Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 19:26:39 -0400
Subject: [PATCH 09/45] Fail a candidate whose standard reforms do not move the
 balance

Plan invariant "Reform responsiveness" (11 Oct 2026). A new mandatory
gate, reform_responsiveness, reads the candidate's metrics report and
fails unless every standard reform ran and, in every horizon year, changed
the government balance in the direction of its expected impact by at
least the tool's reform threshold (GBP 0.1bn), and in the reference year
by at least a share of the expected impact (25%, a proposal pending
d1344). A reform that returns exactly zero or is nearly inert fails; it
never passes as a small number.

The standard set is the metrics tool's own reform list, vendored at the
pinned commit with the tool, plus additional_reforms. The metrics runner
now passes those reforms to the tool, which it did not before, so the
reform costings also enter the review-bounds comparison.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/data/qualification/uk.json   |   8 +
 src/policyengine/provenance/qualification.py  |   1 +
 src/policyengine/provenance/uk_candidate.py   | 292 +++++++++++++++++-
 tests/fixtures/uk_metrics/README.md           |  10 +
 tests/fixtures/uk_metrics/reforms_config.yaml | 136 ++++++++
 tests/test_uk_candidate_gates.py              | 263 +++++++++++++++-
 6 files changed, 693 insertions(+), 17 deletions(-)
 create mode 100644 tests/fixtures/uk_metrics/README.md
 create mode 100644 tests/fixtures/uk_metrics/reforms_config.yaml

diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index e355d94d..5394479f 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -14,6 +14,7 @@
       "repository": "PolicyEngine/policyengine-uk",
       "commit": "073e80809141852eda42127b9e692b17e81343eb",
       "path": "policyengine_uk/utils/aggregate_impact",
+      "reforms_path": "policyengine_uk/tests/microsimulation/reforms_config.yaml",
       "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
     },
     "years": [2025, 2026, 2027, 2028, 2029, 2030, 2031],
@@ -29,6 +30,13 @@
     "compare_to": "latest_certified",
     "poll_timeout_minutes": 360
   },
+  "reform_responsiveness": {
+    "_comment": "Plan invariant 'Reform responsiveness' (11 Oct 2026): each standard reform must move the government balance in the expected direction by a non-trivial amount, or the candidate fails. The standard set is the metrics tool's own reform list (metrics.tool.reforms_path, whose expected impacts come from real runs on the certified pair) plus additional_reforms. A reform passes when it runs and, in every horizon year, its change in gov_balance has the sign of expected_impact and is at least floor_gbp in size (the tool's reform_gbp review threshold); in reference_year it must also be at least min_share_of_expected of |expected_impact|. The share is a proposal pending cos d1344.",
+    "reference_year": 2029,
+    "floor_gbp": 100000000,
+    "min_share_of_expected": 0.25,
+    "additional_reforms": []
+  },
   "promotion": {
     "automatic": false,
     "decision": "cos d1344: automatic promotion and review bounds are methodology calls; until ruled, promotion is a reviewed PR merge."
diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index 41752c66..bddb2b86 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -87,6 +87,7 @@
     "budget_inputs",
     "reform_contract",
     "metrics_review",
+    "reform_responsiveness",
     "replay",
 )
 
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index e7af2a9d..bda4620d 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -986,9 +986,163 @@ def metrics_review(
     )
 
 
+# --- Reform responsiveness -------------------------------------------------------
+
+
+def _fiscal_year(year: int) -> str:
+    return f"{year}-{(year + 1) % 100:02d}"
+
+
+def reform_responsiveness(
+    *,
+    report: Optional[Mapping[str, Any]],
+    standard_reforms: Sequence[Mapping[str, Any]],
+    years: Sequence[int],
+    reference_year: int,
+    floor_gbp: float,
+    min_share_of_expected: float,
+    unavailable_reason: Optional[str] = None,
+) -> GateOutcome:
+    """Every standard reform moves the government balance as expected, or fail.
+
+    ``report`` is the candidate's metrics report, whose ``reforms.``
+    metrics are each reform's change in weighted ``gov_balance`` from a full
+    run. A standard reform passes when all of these hold:
+
+    - it ran (``reform_runs:`` passed) and has a finite value in every
+      year of ``years``;
+    - in every year the change has the sign of its ``expected_impact`` and is
+      at least ``floor_gbp`` in size;
+    - in ``reference_year`` it is at least ``min_share_of_expected`` of
+      ``|expected_impact|`` (given in GBP bn).
+
+    Any failure fails the gate: a reform that silently does nothing is a
+    defect, never a small number to review. The gate is monotone in each
+    reform's response: shrinking a value toward zero or flipping its sign
+    never turns a failure into a pass.
+    """
+
+    if unavailable_reason or report is None:
+        return _result(
+            "reform_responsiveness",
+            "unavailable",
+            unavailable_reason or "No candidate metrics report is available.",
+            {},
+        )
+    if not standard_reforms:
+        return _result(
+            "reform_responsiveness",
+            "unavailable",
+            "No standard reform set is configured.",
+            {},
+        )
+    if reference_year not in years:
+        return _result(
+            "reform_responsiveness",
+            "error",
+            f"The reference year {reference_year} is outside the measured years.",
+            {},
+        )
+    ids: Mapping[str, str] = report.get("reform_ids") or {}
+    checks = {
+        str(row.get("identity_id")): row.get("status")
+        for row in report.get("identities") or []
+    }
+    values = {
+        (str(row.get("metric_id")), row.get("year")): row.get("value")
+        for row in report.get("metrics") or []
+    }
+    problems: list[str] = []
+    configuration: list[str] = []
+    table: list[dict[str, Any]] = []
+    for reform in standard_reforms:
+        name = str(reform.get("name"))
+        expected = reform.get("expected_impact")
+        if (
+            isinstance(expected, bool)
+            or not isinstance(expected, (int, float))
+            or not math.isfinite(expected)
+            or expected == 0
+        ):
+            configuration.append(f"{name!r} has no non-zero expected_impact")
+            continue
+        direction = 1.0 if expected > 0 else -1.0
+        row: dict[str, Any] = {
+            "name": name,
+            "expected_impact_bn": float(expected),
+            "values": {},
+            "problems": [],
+        }
+        table.append(row)
+        reform_id = ids.get(name)
+        if reform_id is None:
+            row["problems"].append("was not run")
+        elif checks.get(f"reform_runs:{reform_id}") != "pass":
+            row["problems"].append("did not run to completion")
+        else:
+            for year in years:
+                value = values.get((f"reforms.{reform_id}", year))
+                if (
+                    isinstance(value, bool)
+                    or not isinstance(value, (int, float))
+                    or not math.isfinite(value)
+                ):
+                    row["problems"].append(f"has no costing for {_fiscal_year(year)}")
+                    continue
+                row["values"][str(year)] = float(value)
+                if value * direction <= 0:
+                    row["problems"].append(
+                        f"moved the balance by £{value:,.0f} in {_fiscal_year(year)}; "
+                        f"expected a {'gain' if direction > 0 else 'cost'}"
+                    )
+                elif abs(value) < floor_gbp:
+                    row["problems"].append(
+                        f"moved the balance by only £{value:,.0f} in "
+                        f"{_fiscal_year(year)} (floor £{floor_gbp:,.0f})"
+                    )
+                elif (
+                    year == reference_year
+                    and abs(value) < min_share_of_expected * abs(expected) * 1e9
+                ):
+                    row["problems"].append(
+                        f"moved the balance by £{value / 1e9:,.2f}bn in "
+                        f"{_fiscal_year(year)}, under {min_share_of_expected:.0%} of "
+                        f"the expected £{expected:,.1f}bn"
+                    )
+        problems.extend(f"{name}: {problem}" for problem in row["problems"])
+    evidence = {
+        "reference_year": reference_year,
+        "floor_gbp": floor_gbp,
+        "min_share_of_expected": min_share_of_expected,
+        "years": list(years),
+        "reforms": table,
+        "candidate_report_sha256": evidence_sha256(report),
+    }
+    if configuration:
+        return _result(
+            "reform_responsiveness", "error", "; ".join(configuration[:8]), evidence
+        )
+    if problems:
+        return _result(
+            "reform_responsiveness",
+            "fail",
+            f"{len(problems)} responsiveness failure(s): " + "; ".join(problems[:6]),
+            evidence,
+        )
+    return _result(
+        "reform_responsiveness",
+        "pass",
+        f"All {len(table)} standard reforms move the government balance in the "
+        f"expected direction in every year from {_fiscal_year(years[0])} to "
+        f"{_fiscal_year(years[-1])}.",
+        evidence,
+    )
+
+
 # --- Metrics tool (W3's aggregate-impact report) ---------------------------------
 
 VENDORED_TOOL_PACKAGE = "pe_uk_aggregate_impact"
+VENDORED_REFORMS_FILE = "reforms_config.yaml"
 PARTITION_PATH_IN_REPO = "policyengine_uk/data/fiscal_partition.yaml"
 
 #: Self-contained runner, executed in any environment that has a policyengine
@@ -1011,15 +1165,23 @@ def metrics_review(
     from policyengine.provenance.dataset_materialization import materialize_dataset
     dataset = materialize_dataset("uk", data_dir=Path(settings["data_dir"])).path
 from policyengine_uk import Microsimulation
+reforms = [
+    {"name": reform["name"], "parameters": reform["parameters"]}
+    for reform in settings.get("reforms") or []
+]
 report = api.compute_budget_metrics(
     Microsimulation(dataset=str(dataset)),
     years=settings["years"],
     partition=partition_module.load_partition(partition_path),
+    reforms=reforms,
     run_guard=settings.get("run_guard", True),
     label=settings.get("label", "candidate"),
 )
 report["partition_source"] = source
 report["dataset_path"] = str(dataset)
+# The tool names each reform's metrics by its own slug of the reform's name.
+slug = importlib.import_module("pe_uk_aggregate_impact.measure").slug
+report["reform_ids"] = {reform["name"]: slug(reform["name"]) for reform in reforms}
 out.write_text(json.dumps(report))
 """
 
@@ -1134,9 +1296,12 @@ def vendor_metrics_tool(
     repository = tool["repository"]
     commit = tool["commit"]
     tool_path = tool["path"].rstrip("/")
+    reforms_path = tool.get("reforms_path")
     root = destination / f"metrics-tool-{commit[:12]}"
     package = root / VENDORED_TOOL_PACKAGE
-    if (package / "api.py").exists():
+    if (package / "api.py").exists() and (
+        not reforms_path or (root / VENDORED_REFORMS_FILE).exists()
+    ):
         return root
     response = get(
         f"https://codeload.github.com/{repository}/tar.gz/{commit}", timeout=120
@@ -1152,6 +1317,8 @@ def vendor_metrics_tool(
                 target = package / relative[len(tool_path) + 1 :]
             elif relative == PARTITION_PATH_IN_REPO:
                 target = root / "fiscal_partition.yaml"
+            elif reforms_path and relative == reforms_path:
+                target = root / VENDORED_REFORMS_FILE
             else:
                 continue
             if ".." in Path(relative).parts:
@@ -1162,9 +1329,36 @@ def vendor_metrics_tool(
             target.write_bytes(extracted.read())
     if not (package / "api.py").exists():
         raise ValueError(f"{repository}@{commit} has no {tool_path}/api.py.")
+    if reforms_path and not (root / VENDORED_REFORMS_FILE).exists():
+        raise ValueError(f"{repository}@{commit} has no {reforms_path}.")
     return root
 
 
+def load_standard_reforms(
+    vendor_root: Optional[Path], settings: Mapping[str, Any]
+) -> list[dict[str, Any]]:
+    """The standard reform set: the tool's own list, then ``additional_reforms``.
+
+    Each entry has ``name``, ``parameters`` and ``expected_impact`` (the
+    change in government balance in the reference year, in GBP bn, from a real
+    run). Names must be unique, so one reform has one definition.
+    """
+
+    reforms: list[dict[str, Any]] = []
+    path = vendor_root / VENDORED_REFORMS_FILE if vendor_root is not None else None
+    if path is not None and path.exists():
+        import yaml  # type: ignore[import-untyped]
+
+        document = yaml.safe_load(path.read_text()) or {}
+        reforms.extend(dict(reform) for reform in document.get("reforms") or [])
+    reforms.extend(dict(reform) for reform in settings.get("additional_reforms") or [])
+    names = [str(reform.get("name")) for reform in reforms]
+    duplicates = sorted({name for name in names if names.count(name) > 1})
+    if duplicates:
+        raise ValueError(f"Standard reforms are defined twice: {duplicates}")
+    return reforms
+
+
 def run_metrics_report(
     python: str,
     vendor_root: Path,
@@ -1175,9 +1369,14 @@ def run_metrics_report(
     data_dir: Optional[Path] = None,
     run_guard: bool = True,
     label: str = "candidate",
+    reforms: Sequence[Mapping[str, Any]] = (),
     run: Optional[Callable[..., Any]] = None,
 ) -> dict[str, Any]:
-    """Compute a metrics report with ``python`` (any environment) via the runner."""
+    """Compute a metrics report with ``python`` (any environment) via the runner.
+
+    ``reforms`` (``name`` and ``parameters``) are costed against the same
+    baseline, each as a full run over ``years``.
+    """
 
     import subprocess
 
@@ -1188,6 +1387,10 @@ def run_metrics_report(
         "data_dir": str(data_dir) if data_dir else None,
         "run_guard": run_guard,
         "label": label,
+        "reforms": [
+            {"name": reform["name"], "parameters": reform["parameters"]}
+            for reform in reforms
+        ],
     }
     run(
         [
@@ -1460,6 +1663,68 @@ def gate_contract() -> GateOutcome:
             expected_dataset_sha256=pair.data.dataset_sha256,
         )
 
+    def metrics_tool() -> Path:
+        if "metrics_tool" not in state:
+            state["metrics_tool"] = vendor_metrics_tool(
+                config["metrics"]["tool"], work_dir, get=requests.get
+            )
+        tool_root: Path = state["metrics_tool"]
+        return tool_root
+
+    def standard_reforms() -> list[dict[str, Any]]:
+        if "standard_reforms" not in state:
+            state["standard_reforms"] = load_standard_reforms(
+                metrics_tool(), config.get("reform_responsiveness") or {}
+            )
+        reforms: list[dict[str, Any]] = state["standard_reforms"]
+        return reforms
+
+    def candidate_metrics() -> dict[str, Any]:
+        """The candidate's report, computed once for both metric gates."""
+
+        import sys
+
+        if "candidate_metrics" not in state:
+            state["candidate_metrics"] = run_metrics_report(
+                sys.executable,
+                metrics_tool(),
+                years=config["metrics"]["years"],
+                out=work_dir / "metrics-candidate.json",
+                dataset_path=dataset(),
+                label="candidate",
+                reforms=standard_reforms(),
+            )
+            state.setdefault("metrics_reports", {})["candidate"] = state[
+                "candidate_metrics"
+            ]
+        report: dict[str, Any] = state["candidate_metrics"]
+        return report
+
+    def gate_responsiveness() -> GateOutcome:
+        settings = config.get("reform_responsiveness")
+        if not settings or not config["metrics"].get("tool"):
+            return reform_responsiveness(
+                report=None,
+                standard_reforms=[],
+                years=[],
+                reference_year=0,
+                floor_gbp=0.0,
+                min_share_of_expected=0.0,
+                unavailable_reason=(
+                    "No reform responsiveness settings or metrics tool is configured."
+                ),
+            )
+        result, evidence = reform_responsiveness(
+            report=candidate_metrics(),
+            standard_reforms=standard_reforms(),
+            years=config["metrics"]["years"],
+            reference_year=int(settings["reference_year"]),
+            floor_gbp=float(settings["floor_gbp"]),
+            min_share_of_expected=float(settings["min_share_of_expected"]),
+        )
+        evidence["tool"] = dict(config["metrics"]["tool"])
+        return result, evidence
+
     def gate_metrics() -> GateOutcome:
         import sys
 
@@ -1480,16 +1745,9 @@ def gate_metrics() -> GateOutcome:
                 unavailable_reason="No previous certificate to compare against.",
             )
         bounds = json.loads((qualification_dir / settings["bounds"]).read_text())
-        vendor_root = vendor_metrics_tool(tool, work_dir, get=requests.get)
+        vendor_root = metrics_tool()
         years = settings["years"]
-        candidate_report = run_metrics_report(
-            sys.executable,
-            vendor_root,
-            years=years,
-            out=work_dir / "metrics-candidate.json",
-            dataset_path=dataset(),
-            label="candidate",
-        )
+        candidate_report = candidate_metrics()
         previous_report = run_metrics_report(
             previous_pair_python(previous_certificate, work_dir),
             vendor_root,
@@ -1497,6 +1755,7 @@ def gate_metrics() -> GateOutcome:
             out=work_dir / "metrics-previous.json",
             data_dir=work_dir / "previous-data",
             label="previous",
+            reforms=standard_reforms(),
         )
         cross_report = None
         if previous_certificate.get("dataset_sha256") != pair.data.dataset_sha256:
@@ -1507,12 +1766,12 @@ def gate_metrics() -> GateOutcome:
                 out=work_dir / "metrics-candidate-model-previous-data.json",
                 dataset_path=Path(previous_report["dataset_path"]),
                 label="candidate model, previous data",
+                reforms=standard_reforms(),
             )
-        state["metrics_reports"] = {
-            "candidate": candidate_report,
-            "previous": previous_report,
-            "candidate_model_previous_data": cross_report,
-        }
+        state.setdefault("metrics_reports", {}).update(
+            previous=previous_report,
+            candidate_model_previous_data=cross_report,
+        )
         result, evidence = metrics_review(
             candidate_report=candidate_report,
             previous_report=previous_report,
@@ -1536,6 +1795,7 @@ def gate_metrics() -> GateOutcome:
         ("budget_inputs", gate_inputs),
         ("reform_contract", gate_contract),
         ("metrics_review", gate_metrics),
+        ("reform_responsiveness", gate_responsiveness),
     ]
     results, evidence = run_gates(gates)
     for name, report in (state.get("metrics_reports") or {}).items():
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
new file mode 100644
index 00000000..549284c5
--- /dev/null
+++ b/tests/fixtures/uk_metrics/README.md
@@ -0,0 +1,10 @@
+# UK metrics tool fixtures
+
+`reforms_config.yaml` is copied unchanged from PolicyEngine/policyengine-uk at
+commit `073e80809141852eda42127b9e692b17e81343eb`
+(`policyengine_uk/tests/microsimulation/reforms_config.yaml`), the commit the
+qualification config pins the metrics tool to. It is the standard reform set
+for the reform responsiveness gate: eight reforms, each with the change in
+weighted government balance in 2029-30 (`expected_impact`, in GBP bn) recorded
+from real runs on the certified pair. `tests/test_uk_candidate_gates.py` reads
+it. Refresh it by copying from the newly pinned commit; never edit it by hand.
diff --git a/tests/fixtures/uk_metrics/reforms_config.yaml b/tests/fixtures/uk_metrics/reforms_config.yaml
new file mode 100644
index 00000000..c48a59ac
--- /dev/null
+++ b/tests/fixtures/uk_metrics/reforms_config.yaml
@@ -0,0 +1,136 @@
+# Regression fixtures for microsimulation reform impacts.
+# These expected impacts are derived from current model output and are used to
+# catch unintended behavior changes. They are not external fiscal estimates
+# unless a reform entry is explicitly annotated otherwise.
+#
+# Each impact is the change in weighted gov_balance in 2029, in £bn, on the
+# dataset below, which must be the one tests/certified_dataset.yaml pins.
+# `receipts` keeps every earlier value with the model and data that produced
+# it, so a change of dataset and a change of model stay separable. Tests ran
+# on whatever enhanced FRS was latest until 2026-04-05, then on uk-data 1.40.3
+# (enhanced_frs_2023_24), and from 2026-10-11 on the certified 1.58.0 pair. The
+# 2026-10-11 receipts on 1.40.3 show how much of each move is the data rather
+# than the model.
+dataset:
+  data_version: 1.58.0
+  path: enhanced_frs_2024_25.h5
+  revision: 47bbb58d3f6467aa4a7059bc6110d2bdcf699b29
+  sha256: 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6
+reforms:
+- name: Raise basic rate by 1pp
+  expected_impact: 7.1
+  parameters:
+    gov.hmrc.income_tax.rates.uk[0].rate: 0.21
+  receipts:
+  - impact: 7.8
+    data: enhanced_frs_2022_23, unpinned (latest at the time)
+    model: 2.34.5 (a1832dc77, #1205, 2025-07-11)
+  - impact: 7.346
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: 7.132
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise higher rate by 1pp
+  expected_impact: 4.6
+  parameters:
+    gov.hmrc.income_tax.rates.uk[1].rate: 0.42
+  receipts:
+  - impact: 4.8
+    data: enhanced_frs_2022_23, unpinned (latest at the time)
+    model: 2.38.1 (fa6eb613e, #1231, 2025-07-15)
+  - impact: 3.961
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: 4.609
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise personal allowance by ~800GBP/year
+  expected_impact: -4.1
+  parameters:
+    gov.hmrc.income_tax.allowances.personal_allowance.amount: 13000
+  receipts:
+  - impact: -4.2
+    data: enhanced_frs_2023_24, unpinned (latest at the time)
+    model: 2.59.0 (53c38d229, #1396, 2025-11-27)
+  - impact: -4.305
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: -4.135
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise child benefit by 25GBP/week per additional child
+  expected_impact: -1.4
+  parameters:
+    gov.hmrc.child_benefit.amount.additional: 25
+  receipts:
+  - impact: -1.2
+    data: enhanced_frs_2022_23, unpinned (latest at the time)
+    model: 2.38.0 (bda6d2ddf, #1228, 2025-07-14)
+  - impact: -1.222
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: -1.428
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Reduce Universal Credit taper rate to 20%
+  expected_impact: -21.3
+  tolerance: 3.0
+  parameters:
+    gov.dwp.universal_credit.means_test.reduction_rate: 0.2
+  receipts:
+  - impact: -18.1
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.78.0 (e4be118a7, #1572, 2026-04-11)
+  - impact: -18.354
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: -21.266
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise Class 1 main employee NICs rate to 10%
+  expected_impact: 12.6
+  parameters:
+    gov.hmrc.national_insurance.class_1.rates.employee.main: 0.1
+  receipts:
+  - impact: 13.0
+    data: enhanced_frs_2023_24, unpinned (latest at the time)
+    model: 2.59.0 (53c38d229, #1396, 2025-11-27)
+  - impact: 13.263
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: 12.566
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise VAT standard rate by 2pp
+  expected_impact: 34.5
+  tolerance: 1.5
+  parameters:
+    gov.hmrc.vat.standard_rate: 0.22
+  # The move from 21.3 is the data: on 1.58.0 recorded full-rate consumption
+  # is 62% higher than on 1.40.3, and the VAT coverage factor (#1996, #2187)
+  # was set on older data.
+  receipts:
+  - impact: 21.3
+    data: enhanced_frs_2023_24, unpinned (latest at the time)
+    model: 2.75.3 (bc59ba950, #1540, 2026-03-29)
+  - impact: 21.222
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: 34.478
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+- name: Raise additional rate by 3pp
+  expected_impact: 3.8
+  parameters:
+    gov.hmrc.income_tax.rates.uk[2].rate: 0.48
+  receipts:
+  - impact: 4.4
+    data: enhanced_frs_2022_23, unpinned (latest at the time)
+    model: 2.35.0 (88bdf190b, #1207, 2025-07-11)
+  - impact: 3.993
+    data: 1.40.3 enhanced_frs_2023_24
+    model: 2.126.8 (6d89338ab, 2026-10-11)
+  - impact: 3.756
+    data: 1.58.0 enhanced_frs_2024_25
+    model: 2.126.8 (6d89338ab, 2026-10-11)
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index bba782a6..8f747a59 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1037,7 +1037,13 @@ def test_inputs_runner_agrees_with_the_gates(
     assert snapshot["supported_years"] == years["supported_years"]
 
 
-def _tool_tarball(commit="c" * 40, include_partition=True):
+REFORMS_FIXTURE = (
+    Path(__file__).parent / "fixtures" / "uk_metrics" / "reforms_config.yaml"
+)
+REFORMS_PATH = "policyengine_uk/tests/microsimulation/reforms_config.yaml"
+
+
+def _tool_tarball(commit="c" * 40, include_partition=True, include_reforms=True):
     import tarfile
 
     buffer = io.BytesIO()
@@ -1049,6 +1055,10 @@ def _tool_tarball(commit="c" * 40, include_partition=True):
     }
     if include_partition:
         files[f"{prefix}/policyengine_uk/data/fiscal_partition.yaml"] = b"heads: []\n"
+    if include_reforms:
+        files[f"{prefix}/policyengine_uk/tests/microsimulation/reforms_config.yaml"] = (
+            REFORMS_FIXTURE.read_bytes()
+        )
     with tarfile.open(fileobj=buffer, mode="w:gz") as archive:
         for name, data in files.items():
             info = tarfile.TarInfo(name)
@@ -1115,6 +1125,257 @@ def run(command, check, cwd):
     assert (python, flag, code) == ("/venv/bin/python", "-c", METRICS_RUNNER)
     assert _json.loads(settings)["years"] == [2026, 2027]
     assert _json.loads(settings)["run_guard"] is True
+    assert _json.loads(settings)["reforms"] == []
+
+
+def test_metrics_report_runner_passes_only_name_and_parameters(tmp_path):
+    import json as _json
+
+    from policyengine.provenance.uk_candidate import (
+        METRICS_RUNNER,
+        load_standard_reforms,
+        run_metrics_report,
+    )
+
+    seen = {}
+
+    def run(command, check, cwd):
+        seen["settings"] = _json.loads(command[-2])
+        Path(command[-1]).write_text(_json.dumps({"status": "ok"}))
+
+    (tmp_path / "reforms_config.yaml").write_bytes(REFORMS_FIXTURE.read_bytes())
+    reforms = load_standard_reforms(tmp_path, {})
+    run_metrics_report(
+        "python",
+        tmp_path,
+        years=[2029],
+        out=tmp_path / "report.json",
+        reforms=reforms,
+        run=run,
+    )
+    assert len(seen["settings"]["reforms"]) == 8
+    assert seen["settings"]["reforms"][0] == {
+        "name": "Raise basic rate by 1pp",
+        "parameters": {"gov.hmrc.income_tax.rates.uk[0].rate": 0.21},
+    }
+    # The runner hands the tool the reforms and reports the tool's own ids.
+    assert "reforms=reforms" in METRICS_RUNNER
+    assert 'report["reform_ids"]' in METRICS_RUNNER
+
+
+def test_the_reform_list_is_vendored_with_the_tool(tmp_path):
+    from policyengine.provenance.uk_candidate import (
+        load_standard_reforms,
+        vendor_metrics_tool,
+    )
+
+    tool = {
+        "repository": "PolicyEngine/policyengine-uk",
+        "commit": "c" * 40,
+        "path": "policyengine_uk/utils/aggregate_impact",
+        "reforms_path": REFORMS_PATH,
+    }
+
+    def get(url, timeout=None):
+        return SimpleNamespace(content=_tool_tarball(), raise_for_status=lambda: None)
+
+    root = vendor_metrics_tool(tool, tmp_path, get=get)
+    reforms = load_standard_reforms(root, {})
+    assert [reform["name"] for reform in reforms][:2] == [
+        "Raise basic rate by 1pp",
+        "Raise higher rate by 1pp",
+    ]
+    assert len(reforms) == 8
+    missing = tmp_path / "missing"
+    with pytest.raises(ValueError, match="reforms_config.yaml"):
+        vendor_metrics_tool(
+            tool,
+            missing,
+            get=lambda url, timeout=None: SimpleNamespace(
+                content=_tool_tarball(include_reforms=False),
+                raise_for_status=lambda: None,
+            ),
+        )
+
+
+def test_a_standard_reform_has_one_definition(tmp_path):
+    from policyengine.provenance.uk_candidate import load_standard_reforms
+
+    (tmp_path / "reforms_config.yaml").write_bytes(REFORMS_FIXTURE.read_bytes())
+    extra = {
+        "name": "Raise the State Pension by 10%",
+        "parameters": {"gov.dwp.state_pension.new_state_pension.amount": 253.3},
+        "expected_impact": -12.0,
+    }
+    reforms = load_standard_reforms(tmp_path, {"additional_reforms": [extra]})
+    assert len(reforms) == 9 and reforms[-1]["name"] == extra["name"]
+    with pytest.raises(ValueError, match="defined twice"):
+        load_standard_reforms(
+            tmp_path,
+            {"additional_reforms": [{**extra, "name": "Raise basic rate by 1pp"}]},
+        )
+    assert load_standard_reforms(None, {}) == []
+
+
+# --- Reform responsiveness -----------------------------------------------------------
+
+RESPONSE_YEARS = [2025, 2026, 2027, 2028, 2029, 2030, 2031]
+
+
+def _standard_reforms():
+    import yaml
+
+    return yaml.safe_load(REFORMS_FIXTURE.read_text())["reforms"]
+
+
+def _slug(name):
+    import re
+
+    return re.sub(r"[^a-z0-9]+", "_", name.lower()).strip("_")
+
+
+def _responsive_report(scale=1.0, overrides=None, years=RESPONSE_YEARS):
+    """A report in which each reform moves the balance by scale x its expected impact."""
+
+    overrides = overrides or {}
+    metrics, identities, ids = [], [], {}
+    for reform in _standard_reforms():
+        reform_id = _slug(reform["name"])
+        ids[reform["name"]] = reform_id
+        identities.append({"identity_id": f"reform_runs:{reform_id}", "status": "pass"})
+        for year in years:
+            value = overrides.get(
+                (reform_id, year), reform["expected_impact"] * 1e9 * scale
+            )
+            if value is not None:
+                metrics.append(
+                    {
+                        "metric_id": f"reforms.{reform_id}",
+                        "year": year,
+                        "value": value,
+                        "kind": "reform",
+                    }
+                )
+    return {
+        "status": "ok",
+        "metrics": metrics,
+        "identities": identities,
+        "reform_ids": ids,
+    }
+
+
+def _responsiveness(report, reforms=None, **kwargs):
+    from policyengine.provenance.uk_candidate import reform_responsiveness
+
+    kwargs.setdefault("years", RESPONSE_YEARS)
+    kwargs.setdefault("reference_year", 2029)
+    kwargs.setdefault("floor_gbp", 1e8)
+    kwargs.setdefault("min_share_of_expected", 0.25)
+    return reform_responsiveness(
+        report=report,
+        standard_reforms=_standard_reforms() if reforms is None else reforms,
+        **kwargs,
+    )[0]
+
+
+def test_reforms_that_respond_as_recorded_pass():
+    result = _responsiveness(_responsive_report())
+    assert result.status == "pass", result.summary
+    assert "All 8 standard reforms" in result.summary
+    assert "2025-26 to 2031-32" in result.summary
+
+
+UC_TAPER = "reduce_universal_credit_taper_rate_to_20"
+BASIC_RATE = "raise_basic_rate_by_1pp"
+
+
+@pytest.mark.parametrize(
+    ("overrides", "fragment"),
+    [
+        (
+            {(UC_TAPER, 2027): 0.0},
+            "moved the balance by £0 in 2027-28; expected a cost",
+        ),
+        ({(UC_TAPER, 2027): -4.0e7}, "by only £-40,000,000 in 2027-28"),
+        ({(BASIC_RATE, 2026): -7.1e9}, "expected a gain"),
+        ({(BASIC_RATE, 2029): 1.0e9}, "under 25% of the expected £7.1bn"),
+        ({(BASIC_RATE, 2030): None}, "has no costing for 2030-31"),
+        ({(BASIC_RATE, 2030): float("nan")}, "has no costing for 2030-31"),
+    ],
+    ids=[
+        "exactly zero",
+        "nearly inert",
+        "wrong sign",
+        "small at reference",
+        "missing",
+        "nan",
+    ],
+)
+def test_a_reform_that_does_not_respond_fails_qualification(overrides, fragment):
+    """The backtest's two modes (exactly £0, nearly inert) and their neighbours."""
+
+    result = _responsiveness(_responsive_report(overrides=overrides))
+    assert result.status == "fail"
+    assert fragment in result.summary, result.summary
+
+
+def test_a_reform_that_did_not_run_fails():
+    report = _responsive_report()
+    for row in report["identities"]:
+        if row["identity_id"] == f"reform_runs:{UC_TAPER}":
+            row["status"] = "fail"
+    assert "did not run to completion" in _responsiveness(report).summary
+    report = _responsive_report()
+    del report["reform_ids"]["Raise VAT standard rate by 2pp"]
+    result = _responsiveness(report)
+    assert result.status == "fail" and "was not run" in result.summary
+
+
+def test_responsiveness_is_never_skipped_or_guessed():
+    assert _responsiveness(None).status == "unavailable"
+    assert _responsiveness(_responsive_report(), reforms=[]).status == "unavailable"
+    assert _responsiveness(_responsive_report(), reference_year=2040).status == "error"
+    unsigned = [{**_standard_reforms()[0], "expected_impact": 0}]
+    assert _responsiveness(_responsive_report(), reforms=unsigned).status == "error"
+    assert qualification_verdict_for("reform_responsiveness", "unavailable") == (
+        "incomplete"
+    )
+    assert qualification_verdict_for("reform_responsiveness", "fail") == "rejected"
+
+
+def qualification_verdict_for(gate_id, status):
+    from policyengine.provenance.qualification import (
+        REQUIRED_GATES,
+        GateResult,
+        qualification_verdict,
+    )
+
+    assert gate_id in REQUIRED_GATES
+    return qualification_verdict(
+        GateResult(
+            gate_id=name, status=status if name == gate_id else "pass", summary="x"
+        )
+        for name in REQUIRED_GATES
+    )
+
+
+@settings(max_examples=100, deadline=None)
+@given(
+    low=st.floats(min_value=-2.0, max_value=3.0),
+    high=st.floats(min_value=-2.0, max_value=3.0),
+)
+def test_responsiveness_is_monotone_in_the_size_of_the_response(low, high):
+    """Shrinking every response, or flipping its sign, never turns fail into pass."""
+
+    low, high = sorted((low, high))
+    order = {"fail": 0, "pass": 1}
+    weaker = _responsiveness(_responsive_report(scale=low)).status
+    stronger = _responsiveness(_responsive_report(scale=high)).status
+    assert order[weaker] <= order[stronger]
+    if low <= 0:
+        assert weaker == "fail"
+    if high >= 0.25:
+        assert stronger == "pass"
 
 
 def test_metrics_with_nan_values_fail_rather_than_crash():

From 4da37e4bf2e87cad6033b093d88c03f302f00939 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 19:44:03 -0400
Subject: [PATCH 10/45] Read the metrics tool's own responsiveness checks

W3 moved the standard reform set and the responsiveness rule into the
metrics tool (policyengine-uk#2335, pinned here at fd944159): ten
reforms, each with the model variable it must move, the direction and
a yearly minimum, checked by the tool as responsive:.

The gate now holds the candidate's report to those checks instead of
keeping a second definition: reform_runs: and responsive: must
be present and passing for every reform in the tool's standard set, the
report must cover the horizon, and the tool's verdict is recomputed from
its reform_targets. values (a disagreement is an error). The runner
no longer passes a reform list, so the tool costs its own set. Both
check families are hard in the metrics review as well.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/data/qualification/uk.json   |  10 +-
 .../data/qualification/uk_review_bounds.json  |   5 +
 src/policyengine/provenance/uk_candidate.py   | 273 +++++++--------
 tests/fixtures/uk_metrics/README.md           |  17 +-
 tests/fixtures/uk_metrics/reforms_config.yaml | 136 --------
 .../fixtures/uk_metrics/standard_reforms.yaml | 106 ++++++
 tests/test_uk_candidate_gates.py              | 324 ++++++++++--------
 7 files changed, 426 insertions(+), 445 deletions(-)
 delete mode 100644 tests/fixtures/uk_metrics/reforms_config.yaml
 create mode 100644 tests/fixtures/uk_metrics/standard_reforms.yaml

diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index 5394479f..b4d157d5 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,9 +12,8 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "073e80809141852eda42127b9e692b17e81343eb",
+      "commit": "fd944159ee27bd1a0f6a664bf537cb98d4b976ae",
       "path": "policyengine_uk/utils/aggregate_impact",
-      "reforms_path": "policyengine_uk/tests/microsimulation/reforms_config.yaml",
       "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
     },
     "years": [2025, 2026, 2027, 2028, 2029, 2030, 2031],
@@ -31,11 +30,8 @@
     "poll_timeout_minutes": 360
   },
   "reform_responsiveness": {
-    "_comment": "Plan invariant 'Reform responsiveness' (11 Oct 2026): each standard reform must move the government balance in the expected direction by a non-trivial amount, or the candidate fails. The standard set is the metrics tool's own reform list (metrics.tool.reforms_path, whose expected impacts come from real runs on the certified pair) plus additional_reforms. A reform passes when it runs and, in every horizon year, its change in gov_balance has the sign of expected_impact and is at least floor_gbp in size (the tool's reform_gbp review threshold); in reference_year it must also be at least min_share_of_expected of |expected_impact|. The share is a proposal pending cos d1344.",
-    "reference_year": 2029,
-    "floor_gbp": 100000000,
-    "min_share_of_expected": 0.25,
-    "additional_reforms": []
+    "_comment": "Plan invariant 'Reform responsiveness' (11 Oct 2026): a reform the model silently ignores must fail qualification. The standard set, each reform's target variable, direction and yearly minimum are the metrics tool's own (standard_reforms.yaml in the pinned tool; the minimums are W3's proposals pending cos d1344). The tool costs the set by default and emits reform_runs: and responsive: checks. This gate requires both checks to be present and passing for every standard reform in the candidate's report, and recomputes each responsive verdict from the report's reform_targets. values.",
+    "standard_reforms_file": "standard_reforms.yaml"
   },
   "promotion": {
     "automatic": false,
diff --git a/src/policyengine/data/qualification/uk_review_bounds.json b/src/policyengine/data/qualification/uk_review_bounds.json
index f19eb4a0..c1c7718b 100644
--- a/src/policyengine/data/qualification/uk_review_bounds.json
+++ b/src/policyengine/data/qualification/uk_review_bounds.json
@@ -69,6 +69,11 @@
       "relative": 0.05,
       "absolute": 100000000.0,
       "why": "5% or \u00a30.1bn on a reference reform costing."
+    },
+    "reform_target": {
+      "relative": 0.05,
+      "absolute": 100000000.0,
+      "why": "5% or \u00a30.1bn on a standard reform's change in its target variable."
     }
   }
 }
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index bda4620d..a0b02de4 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -791,7 +791,15 @@ def _bound(bounds: Mapping[str, Any], kind: Optional[str]) -> tuple[float, float
 
 #: Metric-report check prefixes (``identities[].identity_id``) that fail a
 #: candidate whatever the previous pair did: none fail on main.
-HARD_CHECK_PREFIXES = ("finite:", "weights:", "closure", "identity:", "determinism:")
+HARD_CHECK_PREFIXES = (
+    "finite:",
+    "weights:",
+    "closure",
+    "identity:",
+    "determinism:",
+    "reform_runs:",
+    "responsive:",
+)
 #: Checks that already fail on main for known model defects (for example
 #: ``counted_once:statutory_sick_pay``): they fail a candidate only when the
 #: previous certified pair passed them.
@@ -800,7 +808,6 @@ def _bound(bounds: Mapping[str, Any], kind: Optional[str]) -> tuple[float, float
     "double_count_present:",
     "sign:",
     "bounds:",
-    "reform_runs:",
 )
 
 
@@ -998,28 +1005,28 @@ def reform_responsiveness(
     report: Optional[Mapping[str, Any]],
     standard_reforms: Sequence[Mapping[str, Any]],
     years: Sequence[int],
-    reference_year: int,
-    floor_gbp: float,
-    min_share_of_expected: float,
     unavailable_reason: Optional[str] = None,
 ) -> GateOutcome:
-    """Every standard reform moves the government balance as expected, or fail.
-
-    ``report`` is the candidate's metrics report, whose ``reforms.``
-    metrics are each reform's change in weighted ``gov_balance`` from a full
-    run. A standard reform passes when all of these hold:
-
-    - it ran (``reform_runs:`` passed) and has a finite value in every
-      year of ``years``;
-    - in every year the change has the sign of its ``expected_impact`` and is
-      at least ``floor_gbp`` in size;
-    - in ``reference_year`` it is at least ``min_share_of_expected`` of
-      ``|expected_impact|`` (given in GBP bn).
-
-    Any failure fails the gate: a reform that silently does nothing is a
-    defect, never a small number to review. The gate is monotone in each
-    reform's response: shrinking a value toward zero or flipping its sign
-    never turns a failure into a pass.
+    """Every standard reform ran and moved its target as required, or fail.
+
+    The metrics tool costs its standard reforms and, for each, checks that
+    the weighted total of the reform's target variable moved in the stated
+    direction by at least the stated minimum in every year
+    (``responsive:``), and that the reform ran (``reform_runs:``).
+    This gate holds the candidate's report to that:
+
+    - both checks must be present and ``pass`` for every reform in
+      ``standard_reforms`` (the tool's own list); a missing check is a
+      failure, so a run that costed no reforms cannot pass;
+    - the report must cover exactly ``years``;
+    - the tool's verdict is recomputed here from the report's
+      ``reform_targets.`` values, and a disagreement is an error
+      (differential check of the check).
+
+    Any reform that does not respond fails the gate. There is no review
+    path: a reform the model silently ignores is a defect, never a small
+    number. The gate is monotone: shrinking a reform's response toward zero
+    or flipping its sign never turns a failure into a pass.
     """
 
     if unavailable_reason or report is None:
@@ -1033,95 +1040,70 @@ def reform_responsiveness(
         return _result(
             "reform_responsiveness",
             "unavailable",
-            "No standard reform set is configured.",
-            {},
-        )
-    if reference_year not in years:
-        return _result(
-            "reform_responsiveness",
-            "error",
-            f"The reference year {reference_year} is outside the measured years.",
+            "The metrics tool defines no standard reforms.",
             {},
         )
-    ids: Mapping[str, str] = report.get("reform_ids") or {}
     checks = {
-        str(row.get("identity_id")): row.get("status")
-        for row in report.get("identities") or []
+        str(row.get("identity_id")): row for row in report.get("identities") or []
     }
     values = {
         (str(row.get("metric_id")), row.get("year")): row.get("value")
         for row in report.get("metrics") or []
     }
     problems: list[str] = []
-    configuration: list[str] = []
+    disagreements: list[str] = []
     table: list[dict[str, Any]] = []
+    if report.get("status") not in (None, "ok"):
+        problems.append(f"the report status is {report.get('status')!r}")
+    if sorted(report.get("years") or []) != sorted(years):
+        disagreements.append(
+            f"the report covers {report.get('years')}, not the horizon {list(years)}"
+        )
     for reform in standard_reforms:
-        name = str(reform.get("name"))
-        expected = reform.get("expected_impact")
-        if (
-            isinstance(expected, bool)
-            or not isinstance(expected, (int, float))
-            or not math.isfinite(expected)
-            or expected == 0
-        ):
-            configuration.append(f"{name!r} has no non-zero expected_impact")
-            continue
-        direction = 1.0 if expected > 0 else -1.0
-        row: dict[str, Any] = {
-            "name": name,
-            "expected_impact_bn": float(expected),
-            "values": {},
-            "problems": [],
+        reform_id = reform["id"]
+        sign = 1.0 if reform["direction"] == "up" else -1.0
+        changes: dict[str, Any] = {}
+        recomputed = True
+        for year in years:
+            value = values.get((f"reform_targets.{reform_id}", year))
+            changes[str(year)] = value
+            if (
+                isinstance(value, bool)
+                or not isinstance(value, (int, float))
+                or not math.isfinite(value)
+                or not sign * value >= reform["minimum"]
+            ):
+                recomputed = False
+        ran = (checks.get(f"reform_runs:{reform_id}") or {}).get("status")
+        responsive = checks.get(f"responsive:{reform_id}") or {}
+        row = {
+            **reform,
+            "target_changes": changes,
+            "reform_runs": ran,
+            "responsive": responsive.get("status"),
+            "detail": responsive.get("detail"),
         }
         table.append(row)
-        reform_id = ids.get(name)
-        if reform_id is None:
-            row["problems"].append("was not run")
-        elif checks.get(f"reform_runs:{reform_id}") != "pass":
-            row["problems"].append("did not run to completion")
-        else:
-            for year in years:
-                value = values.get((f"reforms.{reform_id}", year))
-                if (
-                    isinstance(value, bool)
-                    or not isinstance(value, (int, float))
-                    or not math.isfinite(value)
-                ):
-                    row["problems"].append(f"has no costing for {_fiscal_year(year)}")
-                    continue
-                row["values"][str(year)] = float(value)
-                if value * direction <= 0:
-                    row["problems"].append(
-                        f"moved the balance by £{value:,.0f} in {_fiscal_year(year)}; "
-                        f"expected a {'gain' if direction > 0 else 'cost'}"
-                    )
-                elif abs(value) < floor_gbp:
-                    row["problems"].append(
-                        f"moved the balance by only £{value:,.0f} in "
-                        f"{_fiscal_year(year)} (floor £{floor_gbp:,.0f})"
-                    )
-                elif (
-                    year == reference_year
-                    and abs(value) < min_share_of_expected * abs(expected) * 1e9
-                ):
-                    row["problems"].append(
-                        f"moved the balance by £{value / 1e9:,.2f}bn in "
-                        f"{_fiscal_year(year)}, under {min_share_of_expected:.0%} of "
-                        f"the expected £{expected:,.1f}bn"
-                    )
-        problems.extend(f"{name}: {problem}" for problem in row["problems"])
+        label = f"{reform['name']} ({reform_id})"
+        if ran != "pass":
+            problems.append(f"{label} did not run")
+        elif responsive.get("status") != "pass":
+            problems.append(
+                f"{label} did not respond: "
+                + (responsive.get("detail") or "no responsive check in the report")
+            )
+        if ran == "pass" and responsive.get("status") in ("pass", "fail"):
+            if (responsive["status"] == "pass") != recomputed:
+                disagreements.append(
+                    f"{label}: the tool's responsive check is "
+                    f"{responsive['status']} but its reform_targets values "
+                    f"{'meet' if recomputed else 'do not meet'} the minimum"
+                )
     evidence = {
-        "reference_year": reference_year,
-        "floor_gbp": floor_gbp,
-        "min_share_of_expected": min_share_of_expected,
         "years": list(years),
         "reforms": table,
         "candidate_report_sha256": evidence_sha256(report),
     }
-    if configuration:
-        return _result(
-            "reform_responsiveness", "error", "; ".join(configuration[:8]), evidence
-        )
     if problems:
         return _result(
             "reform_responsiveness",
@@ -1129,11 +1111,15 @@ def reform_responsiveness(
             f"{len(problems)} responsiveness failure(s): " + "; ".join(problems[:6]),
             evidence,
         )
+    if disagreements:
+        return _result(
+            "reform_responsiveness", "error", "; ".join(disagreements[:6]), evidence
+        )
     return _result(
         "reform_responsiveness",
         "pass",
-        f"All {len(table)} standard reforms move the government balance in the "
-        f"expected direction in every year from {_fiscal_year(years[0])} to "
+        f"All {len(table)} standard reforms ran and moved their targets by at "
+        f"least their minimums in every year from {_fiscal_year(years[0])} to "
         f"{_fiscal_year(years[-1])}.",
         evidence,
     )
@@ -1142,7 +1128,6 @@ def reform_responsiveness(
 # --- Metrics tool (W3's aggregate-impact report) ---------------------------------
 
 VENDORED_TOOL_PACKAGE = "pe_uk_aggregate_impact"
-VENDORED_REFORMS_FILE = "reforms_config.yaml"
 PARTITION_PATH_IN_REPO = "policyengine_uk/data/fiscal_partition.yaml"
 
 #: Self-contained runner, executed in any environment that has a policyengine
@@ -1165,23 +1150,17 @@ def reform_responsiveness(
     from policyengine.provenance.dataset_materialization import materialize_dataset
     dataset = materialize_dataset("uk", data_dir=Path(settings["data_dir"])).path
 from policyengine_uk import Microsimulation
-reforms = [
-    {"name": reform["name"], "parameters": reform["parameters"]}
-    for reform in settings.get("reforms") or []
-]
+# No ``reforms`` argument: the tool then costs its own standard set and checks
+# each reform's responsiveness (passing [] would cost none).
 report = api.compute_budget_metrics(
     Microsimulation(dataset=str(dataset)),
     years=settings["years"],
     partition=partition_module.load_partition(partition_path),
-    reforms=reforms,
     run_guard=settings.get("run_guard", True),
     label=settings.get("label", "candidate"),
 )
 report["partition_source"] = source
 report["dataset_path"] = str(dataset)
-# The tool names each reform's metrics by its own slug of the reform's name.
-slug = importlib.import_module("pe_uk_aggregate_impact.measure").slug
-report["reform_ids"] = {reform["name"]: slug(reform["name"]) for reform in reforms}
 out.write_text(json.dumps(report))
 """
 
@@ -1296,12 +1275,9 @@ def vendor_metrics_tool(
     repository = tool["repository"]
     commit = tool["commit"]
     tool_path = tool["path"].rstrip("/")
-    reforms_path = tool.get("reforms_path")
     root = destination / f"metrics-tool-{commit[:12]}"
     package = root / VENDORED_TOOL_PACKAGE
-    if (package / "api.py").exists() and (
-        not reforms_path or (root / VENDORED_REFORMS_FILE).exists()
-    ):
+    if (package / "api.py").exists():
         return root
     response = get(
         f"https://codeload.github.com/{repository}/tar.gz/{commit}", timeout=120
@@ -1317,8 +1293,6 @@ def vendor_metrics_tool(
                 target = package / relative[len(tool_path) + 1 :]
             elif relative == PARTITION_PATH_IN_REPO:
                 target = root / "fiscal_partition.yaml"
-            elif reforms_path and relative == reforms_path:
-                target = root / VENDORED_REFORMS_FILE
             else:
                 continue
             if ".." in Path(relative).parts:
@@ -1329,33 +1303,51 @@ def vendor_metrics_tool(
             target.write_bytes(extracted.read())
     if not (package / "api.py").exists():
         raise ValueError(f"{repository}@{commit} has no {tool_path}/api.py.")
-    if reforms_path and not (root / VENDORED_REFORMS_FILE).exists():
-        raise ValueError(f"{repository}@{commit} has no {reforms_path}.")
     return root
 
 
-def load_standard_reforms(
-    vendor_root: Optional[Path], settings: Mapping[str, Any]
-) -> list[dict[str, Any]]:
-    """The standard reform set: the tool's own list, then ``additional_reforms``.
+def load_standard_reforms(vendor_root: Path, filename: str) -> list[dict[str, Any]]:
+    """The metrics tool's standard reform set, read from the vendored tool.
 
-    Each entry has ``name``, ``parameters`` and ``expected_impact`` (the
-    change in government balance in the reference year, in GBP bn, from a real
-    run). Names must be unique, so one reform has one definition.
+    Each entry must carry an ``id`` and a ``responds`` block (``variable``,
+    ``direction`` ``up`` or ``down``, positive ``minimum``): a standard reform
+    with no stated response cannot be held to one, so it is refused.
     """
 
+    import yaml  # type: ignore[import-untyped]
+
+    path = vendor_root / VENDORED_TOOL_PACKAGE / filename
+    if not path.exists():
+        raise ValueError(f"The metrics tool ships no {filename}.")
+    document = yaml.safe_load(path.read_text()) or {}
     reforms: list[dict[str, Any]] = []
-    path = vendor_root / VENDORED_REFORMS_FILE if vendor_root is not None else None
-    if path is not None and path.exists():
-        import yaml  # type: ignore[import-untyped]
-
-        document = yaml.safe_load(path.read_text()) or {}
-        reforms.extend(dict(reform) for reform in document.get("reforms") or [])
-    reforms.extend(dict(reform) for reform in settings.get("additional_reforms") or [])
-    names = [str(reform.get("name")) for reform in reforms]
-    duplicates = sorted({name for name in names if names.count(name) > 1})
-    if duplicates:
-        raise ValueError(f"Standard reforms are defined twice: {duplicates}")
+    for entry in document.get("reforms") or []:
+        responds = entry.get("responds") or {}
+        minimum = responds.get("minimum")
+        if (
+            not entry.get("id")
+            or not responds.get("variable")
+            or responds.get("direction") not in ("up", "down")
+            or isinstance(minimum, bool)
+            or not isinstance(minimum, (int, float))
+            or not minimum > 0
+        ):
+            raise ValueError(
+                f"Standard reform {entry.get('id') or entry.get('name')!r} states "
+                "no id or no expected response."
+            )
+        reforms.append(
+            {
+                "id": str(entry["id"]),
+                "name": str(entry.get("name") or entry["id"]),
+                "variable": str(responds["variable"]),
+                "direction": responds["direction"],
+                "minimum": float(minimum),
+            }
+        )
+    ids = [reform["id"] for reform in reforms]
+    if len(set(ids)) != len(ids):
+        raise ValueError("The standard reform set repeats an id.")
     return reforms
 
 
@@ -1369,13 +1361,12 @@ def run_metrics_report(
     data_dir: Optional[Path] = None,
     run_guard: bool = True,
     label: str = "candidate",
-    reforms: Sequence[Mapping[str, Any]] = (),
     run: Optional[Callable[..., Any]] = None,
 ) -> dict[str, Any]:
     """Compute a metrics report with ``python`` (any environment) via the runner.
 
-    ``reforms`` (``name`` and ``parameters``) are costed against the same
-    baseline, each as a full run over ``years``.
+    The tool also costs its standard reform set against the same baseline,
+    each reform as a full run over ``years``.
     """
 
     import subprocess
@@ -1387,10 +1378,6 @@ def run_metrics_report(
         "data_dir": str(data_dir) if data_dir else None,
         "run_guard": run_guard,
         "label": label,
-        "reforms": [
-            {"name": reform["name"], "parameters": reform["parameters"]}
-            for reform in reforms
-        ],
     }
     run(
         [
@@ -1674,7 +1661,8 @@ def metrics_tool() -> Path:
     def standard_reforms() -> list[dict[str, Any]]:
         if "standard_reforms" not in state:
             state["standard_reforms"] = load_standard_reforms(
-                metrics_tool(), config.get("reform_responsiveness") or {}
+                metrics_tool(),
+                config["reform_responsiveness"]["standard_reforms_file"],
             )
         reforms: list[dict[str, Any]] = state["standard_reforms"]
         return reforms
@@ -1692,7 +1680,6 @@ def candidate_metrics() -> dict[str, Any]:
                 out=work_dir / "metrics-candidate.json",
                 dataset_path=dataset(),
                 label="candidate",
-                reforms=standard_reforms(),
             )
             state.setdefault("metrics_reports", {})["candidate"] = state[
                 "candidate_metrics"
@@ -1707,9 +1694,6 @@ def gate_responsiveness() -> GateOutcome:
                 report=None,
                 standard_reforms=[],
                 years=[],
-                reference_year=0,
-                floor_gbp=0.0,
-                min_share_of_expected=0.0,
                 unavailable_reason=(
                     "No reform responsiveness settings or metrics tool is configured."
                 ),
@@ -1718,9 +1702,6 @@ def gate_responsiveness() -> GateOutcome:
             report=candidate_metrics(),
             standard_reforms=standard_reforms(),
             years=config["metrics"]["years"],
-            reference_year=int(settings["reference_year"]),
-            floor_gbp=float(settings["floor_gbp"]),
-            min_share_of_expected=float(settings["min_share_of_expected"]),
         )
         evidence["tool"] = dict(config["metrics"]["tool"])
         return result, evidence
@@ -1755,7 +1736,6 @@ def gate_metrics() -> GateOutcome:
             out=work_dir / "metrics-previous.json",
             data_dir=work_dir / "previous-data",
             label="previous",
-            reforms=standard_reforms(),
         )
         cross_report = None
         if previous_certificate.get("dataset_sha256") != pair.data.dataset_sha256:
@@ -1766,7 +1746,6 @@ def gate_metrics() -> GateOutcome:
                 out=work_dir / "metrics-candidate-model-previous-data.json",
                 dataset_path=Path(previous_report["dataset_path"]),
                 label="candidate model, previous data",
-                reforms=standard_reforms(),
             )
         state.setdefault("metrics_reports", {}).update(
             previous=previous_report,
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index 549284c5..6f7cd155 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -1,10 +1,11 @@
 # UK metrics tool fixtures
 
-`reforms_config.yaml` is copied unchanged from PolicyEngine/policyengine-uk at
-commit `073e80809141852eda42127b9e692b17e81343eb`
-(`policyengine_uk/tests/microsimulation/reforms_config.yaml`), the commit the
-qualification config pins the metrics tool to. It is the standard reform set
-for the reform responsiveness gate: eight reforms, each with the change in
-weighted government balance in 2029-30 (`expected_impact`, in GBP bn) recorded
-from real runs on the certified pair. `tests/test_uk_candidate_gates.py` reads
-it. Refresh it by copying from the newly pinned commit; never edit it by hand.
+`standard_reforms.yaml` is copied unchanged from PolicyEngine/policyengine-uk at
+commit `fd944159ee27bd1a0f6a664bf537cb98d4b976ae`
+(`policyengine_uk/utils/aggregate_impact/standard_reforms.yaml`), the commit the
+qualification config pins the metrics tool to. It is the tool's standard reform
+set: ten reforms, each with the model variable it must move, the direction and
+the least it must move it in every year. The reform responsiveness gate reads
+the same file from the vendored tool, and `tests/test_uk_candidate_gates.py`
+reads this copy. Refresh it by copying from the newly pinned commit; never
+edit it by hand.
diff --git a/tests/fixtures/uk_metrics/reforms_config.yaml b/tests/fixtures/uk_metrics/reforms_config.yaml
deleted file mode 100644
index c48a59ac..00000000
--- a/tests/fixtures/uk_metrics/reforms_config.yaml
+++ /dev/null
@@ -1,136 +0,0 @@
-# Regression fixtures for microsimulation reform impacts.
-# These expected impacts are derived from current model output and are used to
-# catch unintended behavior changes. They are not external fiscal estimates
-# unless a reform entry is explicitly annotated otherwise.
-#
-# Each impact is the change in weighted gov_balance in 2029, in £bn, on the
-# dataset below, which must be the one tests/certified_dataset.yaml pins.
-# `receipts` keeps every earlier value with the model and data that produced
-# it, so a change of dataset and a change of model stay separable. Tests ran
-# on whatever enhanced FRS was latest until 2026-04-05, then on uk-data 1.40.3
-# (enhanced_frs_2023_24), and from 2026-10-11 on the certified 1.58.0 pair. The
-# 2026-10-11 receipts on 1.40.3 show how much of each move is the data rather
-# than the model.
-dataset:
-  data_version: 1.58.0
-  path: enhanced_frs_2024_25.h5
-  revision: 47bbb58d3f6467aa4a7059bc6110d2bdcf699b29
-  sha256: 5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6
-reforms:
-- name: Raise basic rate by 1pp
-  expected_impact: 7.1
-  parameters:
-    gov.hmrc.income_tax.rates.uk[0].rate: 0.21
-  receipts:
-  - impact: 7.8
-    data: enhanced_frs_2022_23, unpinned (latest at the time)
-    model: 2.34.5 (a1832dc77, #1205, 2025-07-11)
-  - impact: 7.346
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: 7.132
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise higher rate by 1pp
-  expected_impact: 4.6
-  parameters:
-    gov.hmrc.income_tax.rates.uk[1].rate: 0.42
-  receipts:
-  - impact: 4.8
-    data: enhanced_frs_2022_23, unpinned (latest at the time)
-    model: 2.38.1 (fa6eb613e, #1231, 2025-07-15)
-  - impact: 3.961
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: 4.609
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise personal allowance by ~800GBP/year
-  expected_impact: -4.1
-  parameters:
-    gov.hmrc.income_tax.allowances.personal_allowance.amount: 13000
-  receipts:
-  - impact: -4.2
-    data: enhanced_frs_2023_24, unpinned (latest at the time)
-    model: 2.59.0 (53c38d229, #1396, 2025-11-27)
-  - impact: -4.305
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: -4.135
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise child benefit by 25GBP/week per additional child
-  expected_impact: -1.4
-  parameters:
-    gov.hmrc.child_benefit.amount.additional: 25
-  receipts:
-  - impact: -1.2
-    data: enhanced_frs_2022_23, unpinned (latest at the time)
-    model: 2.38.0 (bda6d2ddf, #1228, 2025-07-14)
-  - impact: -1.222
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: -1.428
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Reduce Universal Credit taper rate to 20%
-  expected_impact: -21.3
-  tolerance: 3.0
-  parameters:
-    gov.dwp.universal_credit.means_test.reduction_rate: 0.2
-  receipts:
-  - impact: -18.1
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.78.0 (e4be118a7, #1572, 2026-04-11)
-  - impact: -18.354
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: -21.266
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise Class 1 main employee NICs rate to 10%
-  expected_impact: 12.6
-  parameters:
-    gov.hmrc.national_insurance.class_1.rates.employee.main: 0.1
-  receipts:
-  - impact: 13.0
-    data: enhanced_frs_2023_24, unpinned (latest at the time)
-    model: 2.59.0 (53c38d229, #1396, 2025-11-27)
-  - impact: 13.263
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: 12.566
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise VAT standard rate by 2pp
-  expected_impact: 34.5
-  tolerance: 1.5
-  parameters:
-    gov.hmrc.vat.standard_rate: 0.22
-  # The move from 21.3 is the data: on 1.58.0 recorded full-rate consumption
-  # is 62% higher than on 1.40.3, and the VAT coverage factor (#1996, #2187)
-  # was set on older data.
-  receipts:
-  - impact: 21.3
-    data: enhanced_frs_2023_24, unpinned (latest at the time)
-    model: 2.75.3 (bc59ba950, #1540, 2026-03-29)
-  - impact: 21.222
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: 34.478
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-- name: Raise additional rate by 3pp
-  expected_impact: 3.8
-  parameters:
-    gov.hmrc.income_tax.rates.uk[2].rate: 0.48
-  receipts:
-  - impact: 4.4
-    data: enhanced_frs_2022_23, unpinned (latest at the time)
-    model: 2.35.0 (88bdf190b, #1207, 2025-07-11)
-  - impact: 3.993
-    data: 1.40.3 enhanced_frs_2023_24
-    model: 2.126.8 (6d89338ab, 2026-10-11)
-  - impact: 3.756
-    data: 1.58.0 enhanced_frs_2024_25
-    model: 2.126.8 (6d89338ab, 2026-10-11)
diff --git a/tests/fixtures/uk_metrics/standard_reforms.yaml b/tests/fixtures/uk_metrics/standard_reforms.yaml
new file mode 100644
index 00000000..c2447136
--- /dev/null
+++ b/tests/fixtures/uk_metrics/standard_reforms.yaml
@@ -0,0 +1,106 @@
+# The standard reforms the aggregate-impact report costs on each side.
+#
+# Each reform is either absolute (`parameters`: values applied from 2023, as
+# the reform-cost fixtures in tests/microsimulation/reforms_config.yaml do) or
+# relative (`scale`: each listed parameter is multiplied by the factor in
+# every year of the horizon, starting from that year's baseline value).
+#
+# `responds` states what the reform must do: the model variable whose
+# weighted total it must move, the direction, and the least it must move it
+# in every year of the horizon. A reform that moves its target by less, by
+# nothing or the wrong way fails the `responsive:` check, so a reform the
+# model silently ignores cannot pass as a small number. Each minimum is well
+# below the reform's smallest yearly effect on uk-data 1.58.0 in October 2026
+# (about a fifth of it for most), and is a proposal awaiting the
+# numerical-acceptance ruling (cos d1344). An absolute reform shrinks as the
+# baseline is uprated towards it: the 13,000 personal allowance is worth £4.4bn
+# in 2030-31 but £1.8bn in 2031-32, when the baseline allowance rises to
+# 12,830. From 2032-33 the baseline (13,090) exceeds it, so before the horizon
+# reaches that year, make that reform relative.
+schema_version: 1
+
+reforms:
+  - id: basic_rate_plus_1pp
+    name: Raise basic rate by 1pp
+    parameters:
+      gov.hmrc.income_tax.rates.uk[0].rate: 0.21
+    responds:
+      variable: income_tax
+      direction: up
+      minimum: 1500000000
+  - id: higher_rate_plus_1pp
+    name: Raise higher rate by 1pp
+    parameters:
+      gov.hmrc.income_tax.rates.uk[1].rate: 0.42
+    responds:
+      variable: income_tax
+      direction: up
+      minimum: 1000000000
+  - id: personal_allowance_13000
+    name: Raise personal allowance by ~800GBP/year
+    parameters:
+      gov.hmrc.income_tax.allowances.personal_allowance.amount: 13000
+    responds:
+      variable: income_tax
+      direction: down
+      minimum: 1000000000
+  - id: child_benefit_additional_25
+    name: Raise child benefit by 25GBP/week per additional child
+    parameters:
+      gov.hmrc.child_benefit.amount.additional: 25
+    responds:
+      variable: child_benefit
+      direction: up
+      minimum: 300000000
+  - id: uc_taper_20pc
+    name: Reduce Universal Credit taper rate to 20%
+    parameters:
+      gov.dwp.universal_credit.means_test.reduction_rate: 0.2
+    responds:
+      variable: universal_credit
+      direction: up
+      minimum: 4000000000
+  - id: employee_nics_main_10pc
+    name: Raise Class 1 main employee NICs rate to 10%
+    parameters:
+      gov.hmrc.national_insurance.class_1.rates.employee.main: 0.1
+    responds:
+      variable: national_insurance
+      direction: up
+      minimum: 2500000000
+  - id: vat_standard_plus_2pp
+    name: Raise VAT standard rate by 2pp
+    parameters:
+      gov.hmrc.vat.standard_rate: 0.22
+    responds:
+      variable: vat
+      direction: up
+      minimum: 4000000000
+  - id: additional_rate_plus_3pp
+    name: Raise additional rate by 3pp
+    parameters:
+      gov.hmrc.income_tax.rates.uk[2].rate: 0.48
+    responds:
+      variable: income_tax
+      direction: up
+      minimum: 750000000
+  - id: uc_standard_allowance_plus_10pc
+    name: Raise the Universal Credit standard allowance by 10%
+    scale:
+      gov.dwp.universal_credit.standard_allowance.amount.SINGLE_YOUNG: 1.1
+      gov.dwp.universal_credit.standard_allowance.amount.SINGLE_OLD: 1.1
+      gov.dwp.universal_credit.standard_allowance.amount.COUPLE_YOUNG: 1.1
+      gov.dwp.universal_credit.standard_allowance.amount.COUPLE_OLD: 1.1
+    responds:
+      variable: universal_credit
+      direction: up
+      minimum: 600000000
+  - id: state_pension_plus_10pc
+    name: Raise the State Pension by 10%
+    scale:
+      gov.dwp.state_pension.new_state_pension.amount: 1.1
+      gov.dwp.state_pension.basic_state_pension.amount: 1.1
+    responds:
+      variable: state_pension
+      direction: up
+      minimum: 2500000000
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 8f747a59..e2e26e22 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1037,10 +1037,9 @@ def test_inputs_runner_agrees_with_the_gates(
     assert snapshot["supported_years"] == years["supported_years"]
 
 
-REFORMS_FIXTURE = (
-    Path(__file__).parent / "fixtures" / "uk_metrics" / "reforms_config.yaml"
+STANDARD_REFORMS_FIXTURE = (
+    Path(__file__).parent / "fixtures" / "uk_metrics" / "standard_reforms.yaml"
 )
-REFORMS_PATH = "policyengine_uk/tests/microsimulation/reforms_config.yaml"
 
 
 def _tool_tarball(commit="c" * 40, include_partition=True, include_reforms=True):
@@ -1056,9 +1055,9 @@ def _tool_tarball(commit="c" * 40, include_partition=True, include_reforms=True)
     if include_partition:
         files[f"{prefix}/policyengine_uk/data/fiscal_partition.yaml"] = b"heads: []\n"
     if include_reforms:
-        files[f"{prefix}/policyengine_uk/tests/microsimulation/reforms_config.yaml"] = (
-            REFORMS_FIXTURE.read_bytes()
-        )
+        files[
+            f"{prefix}/policyengine_uk/utils/aggregate_impact/standard_reforms.yaml"
+        ] = STANDARD_REFORMS_FIXTURE.read_bytes()
     with tarfile.open(fileobj=buffer, mode="w:gz") as archive:
         for name, data in files.items():
             info = tarfile.TarInfo(name)
@@ -1091,6 +1090,7 @@ def get(url, timeout=None):
     assert sorted(p.name for p in (root / "pe_uk_aggregate_impact").iterdir()) == [
         "__init__.py",
         "api.py",
+        "standard_reforms.yaml",
     ]
     assert (root / "fiscal_partition.yaml").read_text() == "heads: []\n"
     assert (
@@ -1125,45 +1125,12 @@ def run(command, check, cwd):
     assert (python, flag, code) == ("/venv/bin/python", "-c", METRICS_RUNNER)
     assert _json.loads(settings)["years"] == [2026, 2027]
     assert _json.loads(settings)["run_guard"] is True
-    assert _json.loads(settings)["reforms"] == []
-
+    # The runner must not pass ``reforms``: the tool then costs its own
+    # standard set, whereas an empty list would cost none.
+    assert "reforms=" not in METRICS_RUNNER
 
-def test_metrics_report_runner_passes_only_name_and_parameters(tmp_path):
-    import json as _json
 
-    from policyengine.provenance.uk_candidate import (
-        METRICS_RUNNER,
-        load_standard_reforms,
-        run_metrics_report,
-    )
-
-    seen = {}
-
-    def run(command, check, cwd):
-        seen["settings"] = _json.loads(command[-2])
-        Path(command[-1]).write_text(_json.dumps({"status": "ok"}))
-
-    (tmp_path / "reforms_config.yaml").write_bytes(REFORMS_FIXTURE.read_bytes())
-    reforms = load_standard_reforms(tmp_path, {})
-    run_metrics_report(
-        "python",
-        tmp_path,
-        years=[2029],
-        out=tmp_path / "report.json",
-        reforms=reforms,
-        run=run,
-    )
-    assert len(seen["settings"]["reforms"]) == 8
-    assert seen["settings"]["reforms"][0] == {
-        "name": "Raise basic rate by 1pp",
-        "parameters": {"gov.hmrc.income_tax.rates.uk[0].rate": 0.21},
-    }
-    # The runner hands the tool the reforms and reports the tool's own ids.
-    assert "reforms=reforms" in METRICS_RUNNER
-    assert 'report["reform_ids"]' in METRICS_RUNNER
-
-
-def test_the_reform_list_is_vendored_with_the_tool(tmp_path):
+def test_the_standard_reforms_are_read_from_the_vendored_tool(tmp_path):
     from policyengine.provenance.uk_candidate import (
         load_standard_reforms,
         vendor_metrics_tool,
@@ -1173,48 +1140,57 @@ def test_the_reform_list_is_vendored_with_the_tool(tmp_path):
         "repository": "PolicyEngine/policyengine-uk",
         "commit": "c" * 40,
         "path": "policyengine_uk/utils/aggregate_impact",
-        "reforms_path": REFORMS_PATH,
     }
+    root = vendor_metrics_tool(
+        tool,
+        tmp_path,
+        get=lambda url, timeout=None: SimpleNamespace(
+            content=_tool_tarball(), raise_for_status=lambda: None
+        ),
+    )
+    reforms = load_standard_reforms(root, "standard_reforms.yaml")
+    assert len(reforms) == 10
+    assert reforms[0] == {
+        "id": "basic_rate_plus_1pp",
+        "name": "Raise basic rate by 1pp",
+        "variable": "income_tax",
+        "direction": "up",
+        "minimum": 1.5e9,
+    }
+    assert {reform["id"] for reform in reforms} >= {
+        "uc_standard_allowance_plus_10pc",
+        "state_pension_plus_10pc",
+    }
+    with pytest.raises(ValueError, match="ships no"):
+        load_standard_reforms(root, "missing.yaml")
 
-    def get(url, timeout=None):
-        return SimpleNamespace(content=_tool_tarball(), raise_for_status=lambda: None)
-
-    root = vendor_metrics_tool(tool, tmp_path, get=get)
-    reforms = load_standard_reforms(root, {})
-    assert [reform["name"] for reform in reforms][:2] == [
-        "Raise basic rate by 1pp",
-        "Raise higher rate by 1pp",
-    ]
-    assert len(reforms) == 8
-    missing = tmp_path / "missing"
-    with pytest.raises(ValueError, match="reforms_config.yaml"):
-        vendor_metrics_tool(
-            tool,
-            missing,
-            get=lambda url, timeout=None: SimpleNamespace(
-                content=_tool_tarball(include_reforms=False),
-                raise_for_status=lambda: None,
-            ),
-        )
 
+@pytest.mark.parametrize(
+    "entry",
+    [
+        {
+            "name": "No id",
+            "responds": {"variable": "x", "direction": "up", "minimum": 1},
+        },
+        {"id": "no_response", "name": "No response"},
+        {
+            "id": "bad",
+            "responds": {"variable": "x", "direction": "sideways", "minimum": 1},
+        },
+        {"id": "zero", "responds": {"variable": "x", "direction": "up", "minimum": 0}},
+    ],
+    ids=["no id", "no response", "bad direction", "zero minimum"],
+)
+def test_a_standard_reform_without_a_stated_response_is_refused(tmp_path, entry):
+    import yaml
 
-def test_a_standard_reform_has_one_definition(tmp_path):
     from policyengine.provenance.uk_candidate import load_standard_reforms
 
-    (tmp_path / "reforms_config.yaml").write_bytes(REFORMS_FIXTURE.read_bytes())
-    extra = {
-        "name": "Raise the State Pension by 10%",
-        "parameters": {"gov.dwp.state_pension.new_state_pension.amount": 253.3},
-        "expected_impact": -12.0,
-    }
-    reforms = load_standard_reforms(tmp_path, {"additional_reforms": [extra]})
-    assert len(reforms) == 9 and reforms[-1]["name"] == extra["name"]
-    with pytest.raises(ValueError, match="defined twice"):
-        load_standard_reforms(
-            tmp_path,
-            {"additional_reforms": [{**extra, "name": "Raise basic rate by 1pp"}]},
-        )
-    assert load_standard_reforms(None, {}) == []
+    package = tmp_path / "pe_uk_aggregate_impact"
+    package.mkdir()
+    (package / "standard_reforms.yaml").write_text(yaml.safe_dump({"reforms": [entry]}))
+    with pytest.raises(ValueError):
+        load_standard_reforms(tmp_path, "standard_reforms.yaml")
 
 
 # --- Reform responsiveness -----------------------------------------------------------
@@ -1222,147 +1198,196 @@ def test_a_standard_reform_has_one_definition(tmp_path):
 RESPONSE_YEARS = [2025, 2026, 2027, 2028, 2029, 2030, 2031]
 
 
-def _standard_reforms():
+def _standard_reforms(tmp_path_factory=None):
     import yaml
 
-    return yaml.safe_load(REFORMS_FIXTURE.read_text())["reforms"]
+    return [
+        {
+            "id": entry["id"],
+            "name": entry["name"],
+            "variable": entry["responds"]["variable"],
+            "direction": entry["responds"]["direction"],
+            "minimum": float(entry["responds"]["minimum"]),
+        }
+        for entry in yaml.safe_load(STANDARD_REFORMS_FIXTURE.read_text())["reforms"]
+    ]
+
 
+def _tool_check(reform, changes):
+    """The tool's responsive verdict, restated from reforms.responsiveness()."""
 
-def _slug(name):
-    import re
+    sign = 1.0 if reform["direction"] == "up" else -1.0
+    return bool(changes) and all(
+        sign * change >= reform["minimum"] for change in changes.values()
+    )
 
-    return re.sub(r"[^a-z0-9]+", "_", name.lower()).strip("_")
 
+def _responsive_report(scale=5.0, overrides=None, years=RESPONSE_YEARS, lie=None):
+    """A report in which each reform moves its target by scale x its minimum.
 
-def _responsive_report(scale=1.0, overrides=None, years=RESPONSE_YEARS):
-    """A report in which each reform moves the balance by scale x its expected impact."""
+    ``overrides`` replaces single values (None removes the row). The
+    ``responsive`` checks follow the tool's rule, unless ``lie`` names a
+    reform id whose check is inverted.
+    """
 
     overrides = overrides or {}
-    metrics, identities, ids = [], [], {}
+    metrics, identities = [], []
     for reform in _standard_reforms():
-        reform_id = _slug(reform["name"])
-        ids[reform["name"]] = reform_id
-        identities.append({"identity_id": f"reform_runs:{reform_id}", "status": "pass"})
+        sign = 1.0 if reform["direction"] == "up" else -1.0
+        changes = {}
         for year in years:
             value = overrides.get(
-                (reform_id, year), reform["expected_impact"] * 1e9 * scale
+                (reform["id"], year), sign * reform["minimum"] * scale
             )
             if value is not None:
+                changes[year] = value
                 metrics.append(
                     {
-                        "metric_id": f"reforms.{reform_id}",
+                        "metric_id": f"reform_targets.{reform['id']}",
                         "year": year,
                         "value": value,
-                        "kind": "reform",
+                        "kind": "reform_target",
                     }
                 )
+        finite = {y: v for y, v in changes.items() if v == v}
+        ok = len(finite) == len(years) and _tool_check(reform, finite)
+        if lie == reform["id"]:
+            ok = not ok
+        identities.append(
+            {"identity_id": f"reform_runs:{reform['id']}", "status": "pass"}
+        )
+        identities.append(
+            {
+                "identity_id": f"responsive:{reform['id']}",
+                "status": "pass" if ok else "fail",
+                "detail": "" if ok else f"expected {reform['variable']} to move",
+            }
+        )
     return {
         "status": "ok",
+        "years": list(years),
         "metrics": metrics,
         "identities": identities,
-        "reform_ids": ids,
     }
 
 
-def _responsiveness(report, reforms=None, **kwargs):
+def _responsiveness(report, reforms=None, years=RESPONSE_YEARS):
     from policyengine.provenance.uk_candidate import reform_responsiveness
 
-    kwargs.setdefault("years", RESPONSE_YEARS)
-    kwargs.setdefault("reference_year", 2029)
-    kwargs.setdefault("floor_gbp", 1e8)
-    kwargs.setdefault("min_share_of_expected", 0.25)
     return reform_responsiveness(
         report=report,
         standard_reforms=_standard_reforms() if reforms is None else reforms,
-        **kwargs,
+        years=years,
     )[0]
 
 
-def test_reforms_that_respond_as_recorded_pass():
+def test_reforms_that_all_respond_pass():
     result = _responsiveness(_responsive_report())
     assert result.status == "pass", result.summary
-    assert "All 8 standard reforms" in result.summary
+    assert "All 10 standard reforms" in result.summary
     assert "2025-26 to 2031-32" in result.summary
 
 
-UC_TAPER = "reduce_universal_credit_taper_rate_to_20"
-BASIC_RATE = "raise_basic_rate_by_1pp"
+UC_ALLOWANCE = "uc_standard_allowance_plus_10pc"
+STATE_PENSION = "state_pension_plus_10pc"
 
 
 @pytest.mark.parametrize(
-    ("overrides", "fragment"),
+    ("overrides", "reform_id"),
     [
-        (
-            {(UC_TAPER, 2027): 0.0},
-            "moved the balance by £0 in 2027-28; expected a cost",
-        ),
-        ({(UC_TAPER, 2027): -4.0e7}, "by only £-40,000,000 in 2027-28"),
-        ({(BASIC_RATE, 2026): -7.1e9}, "expected a gain"),
-        ({(BASIC_RATE, 2029): 1.0e9}, "under 25% of the expected £7.1bn"),
-        ({(BASIC_RATE, 2030): None}, "has no costing for 2030-31"),
-        ({(BASIC_RATE, 2030): float("nan")}, "has no costing for 2030-31"),
+        ({(UC_ALLOWANCE, year): 0.0 for year in RESPONSE_YEARS}, UC_ALLOWANCE),
+        ({(STATE_PENSION, year): 4.0e7 for year in RESPONSE_YEARS}, STATE_PENSION),
+        ({(UC_ALLOWANCE, 2027): 0.0}, UC_ALLOWANCE),
+        ({(STATE_PENSION, 2031): -1.3e10}, STATE_PENSION),
+        ({("basic_rate_plus_1pp", 2030): None}, "basic_rate_plus_1pp"),
+        ({("basic_rate_plus_1pp", 2030): float("nan")}, "basic_rate_plus_1pp"),
     ],
     ids=[
         "exactly zero",
         "nearly inert",
+        "one inert year",
         "wrong sign",
-        "small at reference",
         "missing",
         "nan",
     ],
 )
-def test_a_reform_that_does_not_respond_fails_qualification(overrides, fragment):
+def test_a_reform_that_does_not_respond_fails_qualification(overrides, reform_id):
     """The backtest's two modes (exactly £0, nearly inert) and their neighbours."""
 
     result = _responsiveness(_responsive_report(overrides=overrides))
     assert result.status == "fail"
-    assert fragment in result.summary, result.summary
+    assert f"({reform_id}) did not respond" in result.summary, result.summary
+
 
+def test_a_run_that_costed_no_reforms_cannot_pass():
+    """Presence is required: an empty or partial check set is a failure."""
 
-def test_a_reform_that_did_not_run_fails():
     report = _responsive_report()
-    for row in report["identities"]:
-        if row["identity_id"] == f"reform_runs:{UC_TAPER}":
-            row["status"] = "fail"
-    assert "did not run to completion" in _responsiveness(report).summary
+    report["identities"] = []
+    result = _responsiveness(report)
+    assert result.status == "fail" and "did not run" in result.summary
     report = _responsive_report()
-    del report["reform_ids"]["Raise VAT standard rate by 2pp"]
+    report["identities"] = [
+        row
+        for row in report["identities"]
+        if row["identity_id"] != f"responsive:{STATE_PENSION}"
+    ]
     result = _responsiveness(report)
-    assert result.status == "fail" and "was not run" in result.summary
+    assert result.status == "fail"
+    assert "no responsive check in the report" in result.summary
+    report = _responsive_report()
+    for row in report["identities"]:
+        if row["identity_id"] == f"reform_runs:{UC_ALLOWANCE}":
+            row["status"] = "fail"
+    assert f"({UC_ALLOWANCE}) did not run" in _responsiveness(report).summary
 
 
-def test_responsiveness_is_never_skipped_or_guessed():
-    assert _responsiveness(None).status == "unavailable"
-    assert _responsiveness(_responsive_report(), reforms=[]).status == "unavailable"
-    assert _responsiveness(_responsive_report(), reference_year=2040).status == "error"
-    unsigned = [{**_standard_reforms()[0], "expected_impact": 0}]
-    assert _responsiveness(_responsive_report(), reforms=unsigned).status == "error"
-    assert qualification_verdict_for("reform_responsiveness", "unavailable") == (
-        "incomplete"
-    )
-    assert qualification_verdict_for("reform_responsiveness", "fail") == "rejected"
+def test_the_tools_verdict_is_checked_against_its_own_numbers():
+    """Differential: a pass the reform_targets values do not support is an error."""
 
+    inert = {(UC_ALLOWANCE, year): 0.0 for year in RESPONSE_YEARS}
+    lying_pass = _responsive_report(overrides=inert, lie=UC_ALLOWANCE)
+    result = _responsiveness(lying_pass)
+    assert result.status == "error"
+    assert "do not meet the minimum" in result.summary
+    lying_fail = _responsive_report(lie=STATE_PENSION)
+    assert _responsiveness(lying_fail).status == "fail"
+    short = _responsive_report(years=RESPONSE_YEARS[:-1])
+    assert _responsiveness(short).status in ("fail", "error")
 
-def qualification_verdict_for(gate_id, status):
+
+def test_responsiveness_is_never_skipped_or_guessed():
     from policyengine.provenance.qualification import (
         REQUIRED_GATES,
         GateResult,
         qualification_verdict,
     )
 
-    assert gate_id in REQUIRED_GATES
-    return qualification_verdict(
-        GateResult(
-            gate_id=name, status=status if name == gate_id else "pass", summary="x"
-        )
+    assert _responsiveness(None).status == "unavailable"
+    assert _responsiveness(_responsive_report(), reforms=[]).status == "unavailable"
+    assert "reform_responsiveness" in REQUIRED_GATES
+    for status, verdict in (("unavailable", "incomplete"), ("fail", "rejected")):
+        gates = [
+            GateResult(
+                gate_id=name,
+                status=status if name == "reform_responsiveness" else "pass",
+                summary="x",
+            )
+            for name in REQUIRED_GATES
+        ]
+        assert qualification_verdict(gates) == verdict
+    missing = [
+        GateResult(gate_id=name, status="pass", summary="x")
         for name in REQUIRED_GATES
-    )
+        if name != "reform_responsiveness"
+    ]
+    assert qualification_verdict(missing) == "incomplete"
 
 
 @settings(max_examples=100, deadline=None)
 @given(
-    low=st.floats(min_value=-2.0, max_value=3.0),
-    high=st.floats(min_value=-2.0, max_value=3.0),
+    low=st.floats(min_value=-3.0, max_value=6.0),
+    high=st.floats(min_value=-3.0, max_value=6.0),
 )
 def test_responsiveness_is_monotone_in_the_size_of_the_response(low, high):
     """Shrinking every response, or flipping its sign, never turns fail into pass."""
@@ -1372,10 +1397,15 @@ def test_responsiveness_is_monotone_in_the_size_of_the_response(low, high):
     weaker = _responsiveness(_responsive_report(scale=low)).status
     stronger = _responsiveness(_responsive_report(scale=high)).status
     assert order[weaker] <= order[stronger]
-    if low <= 0:
-        assert weaker == "fail"
-    if high >= 0.25:
-        assert stronger == "pass"
+    assert (weaker == "pass") == (low >= 1.0)
+    assert (stronger == "pass") == (high >= 1.0)
+
+
+def test_reform_checks_are_hard_in_the_metrics_review():
+    from policyengine.provenance.uk_candidate import classify_check
+
+    assert classify_check("reform_runs:basic_rate_plus_1pp") == "hard"
+    assert classify_check("responsive:state_pension_plus_10pc") == "hard"
 
 
 def test_metrics_with_nan_values_fail_rather_than_crash():

From 68820f218d59ec503a352d22ed1afd95cc4009b0 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 19:48:33 -0400
Subject: [PATCH 11/45] Follow the metrics tool at c7a6c9639: no-worsening by
 scope, skipped checks

- Pin the metrics tool to policyengine-uk#2335 at c7a6c9639.
- overlap_guard: joins the known-defect checks (it fails on main until
  policyengine-uk#2235), so it fails a candidate only when it worsens.
- A known-defect check has worsened when the previous pair did not fail
  it (passed, skipped or absent), or failed it in fewer scopes, when the
  tool reports failing_scopes on both rows.
- skipped is neither a pass nor a failure; a check the previous pair
  passed that is now skipped needs review.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/data/qualification/uk.json |  2 +-
 src/policyengine/provenance/uk_candidate.py | 57 ++++++++++++-----
 tests/fixtures/uk_metrics/README.md         |  2 +-
 tests/test_uk_candidate_gates.py            | 71 +++++++++++++++++++++
 4 files changed, 115 insertions(+), 17 deletions(-)

diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index b4d157d5..603e3693 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,7 +12,7 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "fd944159ee27bd1a0f6a664bf537cb98d4b976ae",
+      "commit": "c7a6c963991b4873a51042bda640f28eb914e34e",
       "path": "policyengine_uk/utils/aggregate_impact",
       "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
     },
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index a0b02de4..13903549 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -806,6 +806,7 @@ def _bound(bounds: Mapping[str, Any], kind: Optional[str]) -> tuple[float, float
 REGRESSION_CHECK_PREFIXES = (
     "counted_once:",
     "double_count_present:",
+    "overlap_guard:",
     "sign:",
     "bounds:",
 )
@@ -819,6 +820,20 @@ def classify_check(identity_id: str) -> str:
     return "hard"
 
 
+def _wider_failure(candidate: Mapping[str, Any], previous: Mapping[str, Any]) -> bool:
+    """Whether a check failing in both reports fails in a scope it did not before.
+
+    Scopes are years, or ``""`` for a check with no year. Without
+    ``failing_scopes`` on both rows the two failures cannot be told apart, so
+    the failure counts as carried over.
+    """
+
+    now, before = candidate.get("failing_scopes"), previous.get("failing_scopes")
+    if not isinstance(now, list) or not isinstance(before, list):
+        return False
+    return not {str(scope) for scope in now} <= {str(scope) for scope in before}
+
+
 def compare_metric_reports(
     candidate: Mapping[str, Any],
     previous: Mapping[str, Any],
@@ -827,41 +842,47 @@ def compare_metric_reports(
     """``(status, summary, evidence)`` for a candidate against a previous report.
 
     Checks (``identities``) follow the metric tool's classification: hard
-    checks fail outright; known-defect checks fail only as regressions from
-    the previous pair; ``warn`` is recorded, and a check that newly warns
-    where the previous pair passed needs review.
+    checks fail outright; known-defect checks fail only when they worsen
+    against the previous pair, meaning the previous pair did not fail them,
+    or failed them in fewer scopes (``failing_scopes``, when the tool reports
+    them); ``warn`` is recorded, and a check that newly warns, or is skipped
+    where the previous pair passed it, needs review. ``skipped`` is neither a
+    pass nor a failure.
     """
 
     problems: list[str] = []
     review: list[str] = []
     if candidate.get("status") not in (None, "ok"):
         problems.append(f"the candidate report status is {candidate.get('status')!r}")
-    previous_checks = {
-        str(row.get("identity_id")): row.get("status")
-        for row in previous.get("identities", [])
+    previous_rows = {
+        str(row.get("identity_id")): row for row in previous.get("identities", [])
     }
-    hard_failures, regressions, preexisting, new_warnings, warnings_ = (
-        [],
-        [],
-        [],
-        [],
-        [],
-    )
+    hard_failures: list[str] = []
+    regressions: list[str] = []
+    preexisting: list[str] = []
+    new_warnings: list[str] = []
+    warnings_: list[str] = []
+    newly_skipped: list[str] = []
     for row in candidate.get("identities", []):
         check_id = str(row.get("identity_id"))
         status = row.get("status")
-        before = previous_checks.get(check_id)
+        earlier = previous_rows.get(check_id) or {}
+        before = earlier.get("status")
         if status == "fail":
             if classify_check(check_id) == "hard":
                 hard_failures.append(check_id)
-            elif before == "pass" or before is None:
+            elif before != "fail":
                 regressions.append(check_id)
+            elif _wider_failure(row, earlier):
+                regressions.append(f"{check_id} (fails in more scopes)")
             else:
                 preexisting.append(check_id)
         elif status == "warn":
             warnings_.append(check_id)
             if before == "pass":
                 new_warnings.append(check_id)
+        elif status == "skipped" and before == "pass":
+            newly_skipped.append(check_id)
     if hard_failures:
         problems.append(f"checks failed: {', '.join(hard_failures[:8])}")
     if regressions:
@@ -870,6 +891,11 @@ def compare_metric_reports(
         )
     if new_warnings:
         review.append(f"checks newly warn: {', '.join(new_warnings[:8])}")
+    if newly_skipped:
+        review.append(
+            "checks the previous pair passed were skipped: "
+            + ", ".join(newly_skipped[:8])
+        )
     if candidate.get("metrics_version") != previous.get("metrics_version"):
         problems.append(
             "metric definitions differ between the reports "
@@ -930,6 +956,7 @@ def compare_metric_reports(
         "preexisting_check_failures": preexisting,
         "warn_identities": warnings_,
         "new_warnings": new_warnings,
+        "newly_skipped_checks": newly_skipped,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index 6f7cd155..c30cee71 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -1,7 +1,7 @@
 # UK metrics tool fixtures
 
 `standard_reforms.yaml` is copied unchanged from PolicyEngine/policyengine-uk at
-commit `fd944159ee27bd1a0f6a664bf537cb98d4b976ae`
+commit `c7a6c963991b4873a51042bda640f28eb914e34e`
 (`policyengine_uk/utils/aggregate_impact/standard_reforms.yaml`), the commit the
 qualification config pins the metrics tool to. It is the tool's standard reform
 set: ten reforms, each with the model variable it must move, the direction and
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index e2e26e22..36ca3fb7 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -882,6 +882,46 @@ def _checks(**statuses):
         ),
         ({"sign__vat": "fail"}, {}, "fail"),
         ({"bounds__uc": "fail"}, {"bounds__uc": "fail"}, "pass"),
+        # The overlap guard fails on main for a known defect: no-worsening.
+        (
+            {"overlap_guard__property_transaction_tax_geography": "fail"},
+            {"overlap_guard__property_transaction_tax_geography": "fail"},
+            "pass",
+        ),
+        (
+            {"overlap_guard__property_transaction_tax_geography": "fail"},
+            {"overlap_guard__property_transaction_tax_geography": "pass"},
+            "fail",
+        ),
+        # A check skipped before that fails now has worsened.
+        (
+            {"counted_once__statutory_sick_pay": "fail"},
+            {"counted_once__statutory_sick_pay": "skipped"},
+            "fail",
+        ),
+        # Skipped is neither a pass nor a failure, but losing a passing
+        # check needs a look.
+        (
+            {"counted_once__winter_fuel": "skipped"},
+            {"counted_once__winter_fuel": "skipped"},
+            "pass",
+        ),
+        (
+            {"counted_once__winter_fuel": "skipped"},
+            {"counted_once__winter_fuel": "pass"},
+            "needs_review",
+        ),
+        # The reform checks are hard, whatever the previous pair did.
+        (
+            {"responsive__state_pension_plus_10pc": "fail"},
+            {"responsive__state_pension_plus_10pc": "fail"},
+            "fail",
+        ),
+        (
+            {"reform_runs__uc_taper_20pc": "fail"},
+            {"reform_runs__uc_taper_20pc": "fail"},
+            "fail",
+        ),
         # Warnings are recorded; a check that newly warns needs review.
         ({"inert__tobacco_duty": "warn"}, {"inert__tobacco_duty": "warn"}, "pass"),
         (
@@ -900,6 +940,37 @@ def test_check_classification(candidate, previous, status):
     assert result[0] == status, result[1]
 
 
+def test_a_known_failure_that_spreads_to_more_years_has_worsened():
+    """No-worsening by scope: the failing scopes must be a subset of the previous pair's."""
+
+    def check(scopes):
+        return _report(
+            BASE,
+            identities=[
+                {
+                    "identity_id": "sign:vat",
+                    "status": "fail",
+                    "failing_scopes": scopes,
+                }
+            ],
+        )
+
+    same = compare_metric_reports(
+        check(["2026", "2027"]), check(["2026", "2027"]), BOUNDS
+    )
+    fewer = compare_metric_reports(check(["2026"]), check(["2026", "2027"]), BOUNDS)
+    more = compare_metric_reports(
+        check(["2026", "2028"]), check(["2026", "2027"]), BOUNDS
+    )
+    assert (same[0], fewer[0], more[0]) == ("pass", "pass", "fail")
+    assert "sign:vat (fails in more scopes)" in more[1]
+    # Without scopes on both sides the failures cannot be told apart.
+    unscoped = _report(BASE, identities=[{"identity_id": "sign:vat", "status": "fail"}])
+    assert (
+        compare_metric_reports(check(["2026", "2028"]), unscoped, BOUNDS)[0] == "pass"
+    )
+
+
 @settings(max_examples=150, deadline=None)
 @given(
     changes=st.lists(

From 3ea0b190ed6c7a617e3f73ef7a49cec4d582ec67 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 19:52:53 -0400
Subject: [PATCH 12/45] Pin the metrics tool with failing scopes; test on a
 real report

- Pin the metrics tool at policyengine-uk#2335 bd8bff74c, which adds
  failing_scopes to each check row (the only change since c7a6c9639).
- Add W3's real compute_budget_metrics report on uk-data 1.58.0 as a
  fixture: seven years, the overlap guard and the ten standard reforms.
  On it the responsiveness gate passes, the UC standard allowance and
  State Pension reforms clear their minimums in every year, and the four
  checks that fail on main are all no-worsening checks, so a pair
  compared with itself passes.
- The backtest's two failure modes, applied to the real report, fail the
  gate (and are an error while the tool's own check still says pass).

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/data/qualification/uk.json   |     2 +-
 tests/fixtures/uk_metrics/README.md           |    28 +-
 .../uk_metrics/budget_metrics_report.json     | 15671 ++++++++++++++++
 tests/test_uk_candidate_gates.py              |    85 +
 4 files changed, 15776 insertions(+), 10 deletions(-)
 create mode 100644 tests/fixtures/uk_metrics/budget_metrics_report.json

diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index 603e3693..3c60ad51 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,7 +12,7 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "c7a6c963991b4873a51042bda640f28eb914e34e",
+      "commit": "bd8bff74c0baea19c09eedf9ce1391d598d2ffaf",
       "path": "policyengine_uk/utils/aggregate_impact",
       "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
     },
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index c30cee71..dfd8c913 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -1,11 +1,21 @@
 # UK metrics tool fixtures
 
-`standard_reforms.yaml` is copied unchanged from PolicyEngine/policyengine-uk at
-commit `c7a6c963991b4873a51042bda640f28eb914e34e`
-(`policyengine_uk/utils/aggregate_impact/standard_reforms.yaml`), the commit the
-qualification config pins the metrics tool to. It is the tool's standard reform
-set: ten reforms, each with the model variable it must move, the direction and
-the least it must move it in every year. The reform responsiveness gate reads
-the same file from the vendored tool, and `tests/test_uk_candidate_gates.py`
-reads this copy. Refresh it by copying from the newly pinned commit; never
-edit it by hand.
+Both files come from PolicyEngine/policyengine-uk's aggregate-impact tool
+(`policyengine_uk/utils/aggregate_impact/`, policyengine-uk#2335), which the
+qualification config pins at commit
+`bd8bff74c0baea19c09eedf9ce1391d598d2ffaf`.
+`tests/test_uk_candidate_gates.py` reads them. Refresh them from the newly
+pinned commit; never edit them by hand.
+
+- `standard_reforms.yaml`: the tool's standard reform set, copied unchanged.
+  Ten reforms, each with the model variable it must move, the direction and
+  the least it must move it in every year. The reform responsiveness gate
+  reads the same file from the vendored tool.
+- `budget_metrics_report.json`: a real `compute_budget_metrics` report from
+  the tool's owner (workstream W3), run on 11 October 2026 on uk-data 1.58.0
+  (`enhanced_frs_2024_25`) with policyengine-uk main, for 2025-26 to 2031-32,
+  with the overlap guard and the ten standard reforms. It holds aggregates
+  only: 1,470 metric rows and 346 checks (327 pass, 15 warn, 4 fail). It was
+  produced at tool commit `c7a6c963991b4873a51042bda640f28eb914e34e`, one
+  commit before the pin; the only change since adds `failing_scopes` to each
+  check row, so this report has no `failing_scopes`.
diff --git a/tests/fixtures/uk_metrics/budget_metrics_report.json b/tests/fixtures/uk_metrics/budget_metrics_report.json
new file mode 100644
index 00000000..c79f1a06
--- /dev/null
+++ b/tests/fixtures/uk_metrics/budget_metrics_report.json
@@ -0,0 +1,15671 @@
+{
+ "schema": "policyengine-uk-aggregate-impact/1/report",
+ "status": "ok",
+ "metrics_version": "policyengine-uk-aggregate-impact/1+3d0c53d5b453bd14+bf81c943e4ebec5a",
+ "partition_version": "779be6fce5878c1a358e1d921e4427cae51b2cb9391dabf923b5c624ae2d1070",
+ "years": [
+  2025,
+  2026,
+  2027,
+  2028,
+  2029,
+  2030,
+  2031
+ ],
+ "metrics": [
+  {
+   "metric_id": "population.person",
+   "year": 2025,
+   "value": 69712844.3129216,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2026,
+   "value": 69977755.64010108,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2027,
+   "value": 70236674.50701487,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2028,
+   "value": 70517617.61980712,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2029,
+   "value": 70827896.20421527,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2030,
+   "value": 71146624.04218265,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.person",
+   "year": 2031,
+   "value": 71452690.09232165,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "People"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2025,
+   "value": 35436904.67127848,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2026,
+   "value": 35571566.183018014,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2027,
+   "value": 35703181.570698276,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2028,
+   "value": 35845992.467239186,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2029,
+   "value": 36003715.37718047,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2030,
+   "value": 36165733.258539036,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.benunit",
+   "year": 2031,
+   "value": 36321314.823288456,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Benefit units"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2025,
+   "value": 31245113.389789984,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2026,
+   "value": 31363845.951987505,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2027,
+   "value": 31479892.706091657,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2028,
+   "value": 31605810.66237679,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2029,
+   "value": 31744876.701983795,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2030,
+   "value": 31887729.66803205,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "population.household",
+   "year": 2031,
+   "value": 32024907.664337814,
+   "unit": "count",
+   "kind": "population",
+   "partition": null,
+   "label": "Households"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2025,
+   "value": 300493514624.05597,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2026,
+   "value": 320544520884.17847,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2027,
+   "value": 338021251015.9257,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2028,
+   "value": 353227552195.2491,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2029,
+   "value": 369117767213.9463,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2030,
+   "value": 387232407347.2469,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.income_tax",
+   "year": 2031,
+   "value": 411429752919.1772,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "income_tax",
+   "label": "Income tax"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2025,
+   "value": 53131882407.61014,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2026,
+   "value": 55499684495.07545,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2027,
+   "value": 57316093047.9056,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2028,
+   "value": 59021168416.7411,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2029,
+   "value": 60933744650.36868,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2030,
+   "value": 62865473690.570404,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_individual",
+   "year": 2031,
+   "value": 65321678070.619606,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_individual",
+   "label": "National Insurance (employee and self-employed)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2025,
+   "value": 154541037552.12073,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2026,
+   "value": 161154088343.2087,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2027,
+   "value": 166167835008.01767,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2028,
+   "value": 170808399523.67877,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2029,
+   "value": 177113429874.5147,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2030,
+   "value": 182684601617.84186,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.nics_employer",
+   "year": 2031,
+   "value": 189883460588.0551,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "nics_employer",
+   "label": "National Insurance (employer)"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_capital",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_capital",
+   "label": "Employer NI change borne by capital"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.employer_nics_response_consumer",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "employer_nics_response_consumer",
+   "label": "Employer NI change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2025,
+   "value": 12717206634.11718,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2026,
+   "value": 13157373776.93752,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2027,
+   "value": 13652775596.971504,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2028,
+   "value": 14151592611.504883,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2029,
+   "value": 14653801672.085384,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2030,
+   "value": 15204600241.922672,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.capital_gains_tax",
+   "year": 2031,
+   "value": 15768244652.787172,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "capital_gains_tax",
+   "label": "Capital gains tax"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2025,
+   "value": 7830274125.077207,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2026,
+   "value": 8127270450.824548,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2027,
+   "value": 8353117705.791328,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2028,
+   "value": 8562646845.026996,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2029,
+   "value": 8789529758.204428,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2030,
+   "value": 9040980903.523558,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.student_loan_repayments",
+   "year": 2031,
+   "value": 8059998166.851627,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "student_loan_repayments",
+   "label": "Student loan repayments"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2025,
+   "value": 317136171663.45935,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2026,
+   "value": 325663150441.0445,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2027,
+   "value": 333405472036.0278,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2028,
+   "value": 341433856818.8758,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2029,
+   "value": 349794893731.6442,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2030,
+   "value": 358396364144.5514,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat",
+   "year": 2031,
+   "value": 367137164287.62054,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat",
+   "label": "VAT"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.vat_change",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vat_change",
+   "label": "Change in VAT from its baseline"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.private_school_vat",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "private_school_vat",
+   "label": "VAT on private school fees"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2025,
+   "value": 24041873879.224743,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2026,
+   "value": 24144661501.69051,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2027,
+   "value": 26103457396.62795,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2028,
+   "value": 26158807847.977238,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2029,
+   "value": 25887798204.586216,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2030,
+   "value": 25243234770.62697,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.fuel_duty",
+   "year": 2031,
+   "value": 25824982812.576405,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "fuel_duty",
+   "label": "Fuel duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.alcohol_duty",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "alcohol_duty",
+   "label": "Alcohol duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.tobacco_duty",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tobacco_duty",
+   "label": "Tobacco duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.vehicle_excise_duty",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "vehicle_excise_duty",
+   "label": "Vehicle excise duties"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2025,
+   "value": 4306586174.401852,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2026,
+   "value": 4459282492.68721,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2027,
+   "value": 4476138521.654851,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2028,
+   "value": 4496883532.289182,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2029,
+   "value": 4517653126.548064,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2030,
+   "value": 4538717337.874185,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.tv_licence",
+   "year": 2031,
+   "value": 4613696461.117936,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "tv_licence",
+   "label": "TV licence fee"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2025,
+   "value": 49771708157.89493,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2026,
+   "value": 52672603769.35538,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2027,
+   "value": 56014381640.763115,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2028,
+   "value": 59637347359.69022,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2029,
+   "value": 63246644418.46654,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2030,
+   "value": 67017263920.12569,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.council_tax",
+   "year": 2031,
+   "value": 67305565868.62192,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "council_tax",
+   "label": "Council tax"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2028,
+   "value": 493860763.3252144,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2029,
+   "value": 505953941.79338336,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2030,
+   "value": 518394260.7963829,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.high_value_council_tax_surcharge",
+   "year": 2031,
+   "value": 531037020.5527634,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "high_value_council_tax_surcharge",
+   "label": "High value council tax surcharge"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2025,
+   "value": 584068659.0970445,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2026,
+   "value": 611674416.437277,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2027,
+   "value": 640521131.9170634,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2028,
+   "value": 670928666.9686946,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2029,
+   "value": 703059797.6875113,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2030,
+   "value": 736803086.5428002,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.domestic_rates",
+   "year": 2031,
+   "value": 739972742.2779194,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "domestic_rates",
+   "label": "Northern Ireland domestic rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2025,
+   "value": 31732500424.943848,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2026,
+   "value": 31732499121.74478,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2027,
+   "value": 31732496311.19231,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2028,
+   "value": 31732499335.602257,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2029,
+   "value": 31732495775.940987,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2030,
+   "value": 31732497033.93507,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.business_rates",
+   "year": 2031,
+   "value": 31732498138.642197,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "business_rates",
+   "label": "Business rates"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2025,
+   "value": 19447521756.60174,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2026,
+   "value": 20439906422.593903,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2027,
+   "value": 21414316294.15224,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2028,
+   "value": 22393098228.154316,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2029,
+   "value": 23394928012.007107,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2030,
+   "value": 24493314488.64765,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.sdlt_household",
+   "year": 2031,
+   "value": 25645659350.923958,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "sdlt_household",
+   "label": "Stamp duty land tax (own purchases, and corporate until the"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2025,
+   "value": 2926955.7028617123,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2026,
+   "value": 3159363.4106524643,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2027,
+   "value": 3426934.00067959,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2028,
+   "value": 3700930.558409606,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2029,
+   "value": 3976395.985409789,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2030,
+   "value": 4283730.381307287,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_transaction_tax",
+   "year": 2031,
+   "value": 4617409.568686154,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_transaction_tax",
+   "label": "Land transaction tax (Wales)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2025,
+   "value": 99491389.10783455,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2026,
+   "value": 103957133.89622791,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2027,
+   "value": 109071438.72328326,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2028,
+   "value": 114234820.44540606,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2029,
+   "value": 119415529.40185314,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2030,
+   "value": 125108787.1325237,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.land_and_buildings_transaction_tax",
+   "year": 2031,
+   "value": 130998504.05282259,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_and_buildings_transaction_tax",
+   "label": "Land and buildings transaction tax (Scotland)"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.corporate_incident_tax_change",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "corporate_incident_tax_change",
+   "label": "Unspecified tax change borne by capital"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.consumer_incident_tax_change",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "consumer_incident_tax_change",
+   "label": "Unspecified tax change borne by consumers"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.wealth_tax",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "wealth_tax",
+   "label": "Wealth tax"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.non_primary_residence_wealth_tax",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "non_primary_residence_wealth_tax",
+   "label": "Wealth tax excluding the main residence"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.land_value_tax",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "land_value_tax",
+   "label": "Land value tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "receipts.carbon_tax",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "receipt",
+   "partition": "carbon_tax",
+   "label": "Carbon tax"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2025,
+   "value": 123608843187.93976,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2026,
+   "value": 128313805027.58318,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2027,
+   "value": 130127006024.04692,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2028,
+   "value": 132238843074.43095,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2029,
+   "value": 136141146063.11377,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2030,
+   "value": 140172899465.68817,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.state_pension",
+   "year": 2031,
+   "value": 144295261485.49826,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2025,
+   "value": 11410127.781640545,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2026,
+   "value": 11314830.782796293,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2027,
+   "value": 11062132.340065777,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2028,
+   "value": 10978110.546501547,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2029,
+   "value": 11026414.415012136,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2030,
+   "value": 11076033.608679011,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "caseloads.state_pension",
+   "year": 2031,
+   "value": 11123681.665928766,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "state_pension",
+   "label": "State Pension"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2025,
+   "value": 6693405148.200283,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2026,
+   "value": 7053483709.162087,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2027,
+   "value": 7033310841.277825,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2028,
+   "value": 7106016715.233224,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2029,
+   "value": 7226848094.900362,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2030,
+   "value": 7357686467.835372,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.pension_credit",
+   "year": 2031,
+   "value": 6706505197.30149,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2025,
+   "value": 1482756.0540938377,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2026,
+   "value": 1480853.1148245037,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2027,
+   "value": 1468135.4329868257,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2028,
+   "value": 1447010.371819973,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2029,
+   "value": 1447749.8420774192,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2030,
+   "value": 1444977.4954886883,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "caseloads.pension_credit",
+   "year": 2031,
+   "value": 1071942.0777988583,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pension_credit",
+   "label": "Pension Credit"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2025,
+   "value": 1703858030.6710334,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2026,
+   "value": 1687685652.7937918,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2027,
+   "value": 1616450871.1886823,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2028,
+   "value": 1595491327.4155288,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2029,
+   "value": 1589373766.706106,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2030,
+   "value": 1572193208.341339,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.winter_fuel_payment",
+   "year": 2031,
+   "value": 1561450492.8642156,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2025,
+   "value": 7112673.635766387,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2026,
+   "value": 7034862.558265865,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2027,
+   "value": 6701440.449254692,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2028,
+   "value": 6595675.344529897,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2029,
+   "value": 6562245.612942323,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2030,
+   "value": 6475253.517584786,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "caseloads.winter_fuel_payment",
+   "year": 2031,
+   "value": 6396321.154249236,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "winter_fuel_payment",
+   "label": "Winter Fuel Payment"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2025,
+   "value": 195652682.01216725,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2026,
+   "value": 203249126.6687394,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2027,
+   "value": 207355049.2189332,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2028,
+   "value": 211194062.34368283,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2029,
+   "value": 216365284.1364411,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2030,
+   "value": 221685784.68137968,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.pawhp",
+   "year": 2031,
+   "value": 227092425.0723793,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2025,
+   "value": 829304.9473122358,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2026,
+   "value": 829534.2019373178,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2027,
+   "value": 829233.4100881219,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2028,
+   "value": 827297.3866233826,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2029,
+   "value": 830937.4991832376,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2030,
+   "value": 834676.7390937805,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.pawhp",
+   "year": 2031,
+   "value": 838267.4468256831,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pawhp",
+   "label": "Pension Age Winter Heating Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2025,
+   "value": 79297069929.09415,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2026,
+   "value": 83589492640.30864,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2027,
+   "value": 85214410402.33775,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2028,
+   "value": 86751184502.34996,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2029,
+   "value": 87589733492.11055,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2030,
+   "value": 84522628500.50685,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.universal_credit",
+   "year": 2031,
+   "value": 84959856870.21652,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2025,
+   "value": 6348321.546875536,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2026,
+   "value": 6360591.7880883515,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2027,
+   "value": 6371549.96376504,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2028,
+   "value": 6387956.646527201,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2029,
+   "value": 6368112.714898095,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2030,
+   "value": 6306509.543026373,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "caseloads.universal_credit",
+   "year": 2031,
+   "value": 6290932.269934744,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_credit",
+   "label": "Universal Credit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2025,
+   "value": 8156481113.662994,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2026,
+   "value": 8481531600.187535,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2027,
+   "value": 8730679159.952463,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2028,
+   "value": 8864953021.672188,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2029,
+   "value": 9128777068.594437,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2030,
+   "value": 9364726526.233978,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.housing_benefit",
+   "year": 2031,
+   "value": 7910651616.326078,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2025,
+   "value": 1231862.2140089273,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2026,
+   "value": 1232121.5733534694,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2027,
+   "value": 1233595.1880552769,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2028,
+   "value": 1219421.9009352624,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2029,
+   "value": 1224496.4099243134,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2030,
+   "value": 1225629.5051008165,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "caseloads.housing_benefit",
+   "year": 2031,
+   "value": 1040899.9826000333,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "housing_benefit",
+   "label": "Housing Benefit"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2025,
+   "value": 2113520041.1605535,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2026,
+   "value": 2160301971.6342654,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2027,
+   "value": 2208773724.380773,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2028,
+   "value": 2263288488.6852794,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2029,
+   "value": 2318590052.1342373,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2030,
+   "value": 2383255853.6602764,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.council_tax_reduction",
+   "year": 2031,
+   "value": 2140059095.905221,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2025,
+   "value": 3390071.4158337414,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2026,
+   "value": 3414428.1972658634,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2027,
+   "value": 3432134.60831666,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2028,
+   "value": 3454574.494795531,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2029,
+   "value": 3471370.6449995935,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2030,
+   "value": 3503850.509585738,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "caseloads.council_tax_reduction",
+   "year": 2031,
+   "value": 3284019.218611926,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "council_tax_reduction",
+   "label": "Council Tax Reduction"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2025,
+   "value": 2157918345.897898,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2026,
+   "value": 2215460941.2027354,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2027,
+   "value": 2267178997.307175,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2028,
+   "value": 2318791077.751506,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2029,
+   "value": 2374655132.983756,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2030,
+   "value": 2432303236.337222,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_income",
+   "year": 2031,
+   "value": 2490528072.8603873,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2025,
+   "value": 188801.45329512656,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2026,
+   "value": 189518.90480037034,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2027,
+   "value": 190220.12851785123,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2028,
+   "value": 190792.28100878,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2029,
+   "value": 191631.7696904242,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2030,
+   "value": 192494.11825346947,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "caseloads.esa_income",
+   "year": 2031,
+   "value": 193322.20888361335,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_income",
+   "label": "Employment and Support Allowance (income-related)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2025,
+   "value": 5185465918.024606,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2026,
+   "value": 5324889662.558813,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2027,
+   "value": 5451483839.668319,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2028,
+   "value": 5582755219.611585,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2029,
+   "value": 5719465848.776321,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2030,
+   "value": 5860107436.9060955,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.esa_contrib",
+   "year": 2031,
+   "value": 6003027242.14748,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2025,
+   "value": 716681.2252025008,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2026,
+   "value": 719404.6381566375,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2027,
+   "value": 722066.4522648603,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2028,
+   "value": 724954.6817337871,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2029,
+   "value": 728144.496014744,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2030,
+   "value": 731421.169972077,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.esa_contrib",
+   "year": 2031,
+   "value": 734567.6720936149,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "esa_contrib",
+   "label": "Employment and Support Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2025,
+   "value": 2091746.573322478,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2025,
+   "value": 428.6262260079384,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_income",
+   "label": "Jobseeker's Allowance (income-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2025,
+   "value": 297414211.9393128,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2026,
+   "value": 305410902.6767736,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2027,
+   "value": 312671758.9873353,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2028,
+   "value": 320200875.2165054,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2029,
+   "value": 328041963.6404445,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2030,
+   "value": 336108514.2782755,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.jsa_contrib",
+   "year": 2031,
+   "value": 344305739.25844115,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2025,
+   "value": 69247.07556176186,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2026,
+   "value": 69510.21602272987,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2027,
+   "value": 69767.40603733063,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2028,
+   "value": 70046.47099995613,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2029,
+   "value": 70354.67849779129,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2030,
+   "value": 70671.27628540993,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "caseloads.jsa_contrib",
+   "year": 2031,
+   "value": 70975.29594826698,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "jsa_contrib",
+   "label": "Jobseeker's Allowance (contribution-based)"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2025,
+   "value": 168861494.13127527,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.income_support",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2025,
+   "value": 34027.1418364048,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "caseloads.income_support",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "income_support",
+   "label": "Income Support"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.working_tax_credit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.working_tax_credit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "working_tax_credit",
+   "label": "Working Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.child_tax_credit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "caseloads.child_tax_credit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_tax_credit",
+   "label": "Child Tax Credit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.incapacity_benefit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "caseloads.incapacity_benefit",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "incapacity_benefit",
+   "label": "Incapacity Benefit"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2025,
+   "value": 26930742886.35225,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2026,
+   "value": 28062341229.807953,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2027,
+   "value": 28813932611.682465,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2028,
+   "value": 29507723865.475834,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2029,
+   "value": 30230279635.690178,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2030,
+   "value": 30973577012.717224,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.pip",
+   "year": 2031,
+   "value": 31728969558.821815,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2025,
+   "value": 3561191.43436794,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2026,
+   "value": 3574724.089687288,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2027,
+   "value": 3587950.6320851147,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2028,
+   "value": 3602302.242634833,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2029,
+   "value": 3618152.4307922274,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2030,
+   "value": 3634434.2309794426,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "caseloads.pip",
+   "year": 2031,
+   "value": 3650069.225597918,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "pip",
+   "label": "Personal Independence Payment"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2025,
+   "value": 7484533549.186283,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2026,
+   "value": 7798317749.580545,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2027,
+   "value": 8007179295.781675,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2028,
+   "value": 8199978749.538992,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2029,
+   "value": 8400772001.314109,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2030,
+   "value": 8607328838.619286,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.dla",
+   "year": 2031,
+   "value": 8817246875.370478,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2025,
+   "value": 1334888.5791397095,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2026,
+   "value": 1339961.2010401338,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2027,
+   "value": 1344919.083814323,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2028,
+   "value": 1350298.687692389,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2029,
+   "value": 1356240.0184779614,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2030,
+   "value": 1362343.138695091,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "caseloads.dla",
+   "year": 2031,
+   "value": 1368203.8070302308,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "dla",
+   "label": "Disability Living Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2025,
+   "value": 8738849002.944973,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2026,
+   "value": 9105426589.661386,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2027,
+   "value": 9349296216.992481,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2028,
+   "value": 9574411518.877106,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2029,
+   "value": 9808860827.118614,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2030,
+   "value": 10050039243.53858,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.attendance_allowance",
+   "year": 2031,
+   "value": 10295142509.771086,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2025,
+   "value": 1716598.859297052,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2026,
+   "value": 1723121.9867911339,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2027,
+   "value": 1729497.5712008923,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2028,
+   "value": 1736415.4675818533,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2029,
+   "value": 1744055.7271453738,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2030,
+   "value": 1751904.025848925,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "caseloads.attendance_allowance",
+   "year": 2031,
+   "value": 1759440.5596084595,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "attendance_allowance",
+   "label": "Attendance Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2025,
+   "value": 4648737205.678978,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2026,
+   "value": 4842862964.368323,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2027,
+   "value": 4972568907.329457,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2028,
+   "value": 5092300033.036156,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2029,
+   "value": 5216995990.439329,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2030,
+   "value": 5345270444.763329,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carers_allowance",
+   "year": 2031,
+   "value": 5475632307.34242,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2025,
+   "value": 1073214.7707251012,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2026,
+   "value": 1077293.0261095166,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2027,
+   "value": 1081279.032247901,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2028,
+   "value": 1085604.089460224,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2029,
+   "value": 1090380.7663949132,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2030,
+   "value": 1095287.5083169043,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "caseloads.carers_allowance",
+   "year": 2031,
+   "value": 1099999.3295924067,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carers_allowance",
+   "label": "Carer's Allowance"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2025,
+   "value": 375132605.30346316,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2026,
+   "value": 390797693.02699834,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2027,
+   "value": 401264392.71339667,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2028,
+   "value": 410926172.48663545,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2029,
+   "value": 420988584.3188077,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2030,
+   "value": 431339766.7553348,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.carer_support_payment",
+   "year": 2031,
+   "value": 441859394.4117867,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2025,
+   "value": 86603.70229154825,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2026,
+   "value": 86932.79830861092,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2027,
+   "value": 87254.451836586,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2028,
+   "value": 87603.46610051394,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2029,
+   "value": 87988.92237108946,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2030,
+   "value": 88384.87467557192,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.carer_support_payment",
+   "year": 2031,
+   "value": 88765.09786373377,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "carer_support_payment",
+   "label": "Carer Support Payment (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2026,
+   "value": 52889916.61334165,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2027,
+   "value": 53085610.62761456,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2028,
+   "value": 53297950.914309174,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2029,
+   "value": 53532462.518737875,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2030,
+   "value": 53773359.910451815,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.scottish_carer_supplement",
+   "year": 2031,
+   "value": 54004687.70741227,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2026,
+   "value": 86932.79830861092,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2027,
+   "value": 87254.451836586,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2028,
+   "value": 87603.46610051394,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2029,
+   "value": 87988.92237108946,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2030,
+   "value": 88384.87467557192,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "caseloads.scottish_carer_supplement",
+   "year": 2031,
+   "value": 88765.09786373377,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_carer_supplement",
+   "label": "Carer's Allowance Supplement (Scotland)"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2025,
+   "value": 22916850.46898842,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2026,
+   "value": 23874085.23946771,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2027,
+   "value": 24513501.268621735,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2028,
+   "value": 25103746.46338744,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2029,
+   "value": 25718463.554498497,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2030,
+   "value": 26350824.69866039,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.sda",
+   "year": 2031,
+   "value": 26993475.082385655,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2025,
+   "value": 3832.2492423057556,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2026,
+   "value": 3846.8119764328003,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2027,
+   "value": 3861.0452857017517,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2028,
+   "value": 3876.4891839027405,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2029,
+   "value": 3893.5458583831787,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2030,
+   "value": 3911.066900253296,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "caseloads.sda",
+   "year": 2031,
+   "value": 3927.8920154571533,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "sda",
+   "label": "Severe Disablement Allowance"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2025,
+   "value": 507122677.50677097,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2026,
+   "value": 520757913.07925874,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2027,
+   "value": 533138408.2492215,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2028,
+   "value": 545976365.926789,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2029,
+   "value": 559346215.9575605,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2030,
+   "value": 573100581.8244832,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.iidb",
+   "year": 2031,
+   "value": 587077716.6684005,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2025,
+   "value": 136309.47050744295,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2026,
+   "value": 136827.45147165656,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2027,
+   "value": 137333.71539336443,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2028,
+   "value": 137883.04356488585,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2029,
+   "value": 138489.7313208878,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2030,
+   "value": 139112.9398522377,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "caseloads.iidb",
+   "year": 2031,
+   "value": 139711.38968542218,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "iidb",
+   "label": "Industrial Injuries Disablement Benefit"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2025,
+   "value": 568151093.7335573,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2026,
+   "value": 583427211.5685618,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2027,
+   "value": 597297627.7972465,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2028,
+   "value": 611680516.7185693,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2029,
+   "value": 626659337.1968452,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2030,
+   "value": 642068929.7703295,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.afcs",
+   "year": 2031,
+   "value": 657728126.7655065,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2025,
+   "value": 87231.42297008634,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2026,
+   "value": 87562.9048769474,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2027,
+   "value": 87886.88816124201,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2028,
+   "value": 88238.43054047227,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2029,
+   "value": 88626.6806499958,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2030,
+   "value": 89025.50376203656,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "caseloads.afcs",
+   "year": 2031,
+   "value": 89408.48312401772,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "afcs",
+   "label": "Armed Forces Compensation Scheme"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2025,
+   "value": 16225320972.639776,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2026,
+   "value": 16896152580.691387,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2027,
+   "value": 17341380924.037914,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2028,
+   "value": 17755008028.657654,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2029,
+   "value": 18184587501.076538,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2030,
+   "value": 18623367766.380272,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.child_benefit",
+   "year": 2031,
+   "value": 19051556819.483387,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2025,
+   "value": 8144503.8247400075,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2026,
+   "value": 8170465.289068207,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2027,
+   "value": 8197312.676083803,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2028,
+   "value": 8228525.797302961,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2029,
+   "value": 8262403.058013514,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2030,
+   "value": 8295971.741483018,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "caseloads.child_benefit",
+   "year": 2031,
+   "value": 8318393.685991436,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "child_benefit",
+   "label": "Child Benefit"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2025,
+   "value": 497726869.8419192,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2026,
+   "value": 519612809.90459955,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2027,
+   "value": 533556568.34392536,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2028,
+   "value": 546831672.8782737,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2029,
+   "value": 557690457.6552503,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2030,
+   "value": 571385467.1006676,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.scottish_child_payment",
+   "year": 2031,
+   "value": 579782864.4065932,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2025,
+   "value": 352547.7069185972,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2026,
+   "value": 354345.8819241524,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2027,
+   "value": 355656.9695440531,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2028,
+   "value": 357079.5769625902,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2029,
+   "value": 356899.05693626404,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2030,
+   "value": 358505.11331129074,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "caseloads.scottish_child_payment",
+   "year": 2031,
+   "value": 356640.845736742,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "scottish_child_payment",
+   "label": "Scottish Child Payment"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.two_child_limit_payment",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "caseloads.two_child_limit_payment",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "two_child_limit_payment",
+   "label": "Two Child Limit Payment (Scotland, counterfactual)"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2025,
+   "value": 53970826.290031455,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2026,
+   "value": 54175917.177720994,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2027,
+   "value": 54376369.043138646,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2028,
+   "value": 54593871.5011113,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2029,
+   "value": 54834085.12924674,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2030,
+   "value": 55080840.175692044,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.healthy_start_vouchers",
+   "year": 2031,
+   "value": 55317793.086847685,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2025,
+   "value": 208602.1595891416,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2026,
+   "value": 209394.85441070795,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2027,
+   "value": 210169.61887291074,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2028,
+   "value": 211010.2855282426,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2029,
+   "value": 211938.73312041163,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2030,
+   "value": 212892.46397477388,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "caseloads.healthy_start_vouchers",
+   "year": 2031,
+   "value": 213808.30855458975,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "healthy_start_vouchers",
+   "label": "Healthy Start vouchers"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.maternity_allowance",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "caseloads.maternity_allowance",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "maternity_allowance",
+   "label": "Maternity Allowance"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2025,
+   "value": 3337974284.302048,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2026,
+   "value": 3427723791.796866,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2027,
+   "value": 3509214573.900618,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2028,
+   "value": 3593716240.856939,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2029,
+   "value": 3681719191.086521,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2030,
+   "value": 3772252863.671072,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_maternity_pay",
+   "year": 2031,
+   "value": 3864252917.3662605,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2025,
+   "value": 321312.8473469913,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2026,
+   "value": 322533.84839725494,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2027,
+   "value": 323727.22941863537,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2028,
+   "value": 325022.1207540333,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2029,
+   "value": 326452.22118473053,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2030,
+   "value": 327921.2663208842,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_maternity_pay",
+   "year": 2031,
+   "value": 329331.95074787736,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_maternity_pay",
+   "label": "Statutory Maternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2025,
+   "value": 1179772370.051021,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2026,
+   "value": 1211493383.3111763,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2027,
+   "value": 1240295431.5737867,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2028,
+   "value": 1270161726.4028587,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2029,
+   "value": 1301265465.0001216,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2030,
+   "value": 1333263686.1531434,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.statutory_sick_pay",
+   "year": 2031,
+   "value": 1365780194.8969457,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2025,
+   "value": 185810.46695950627,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2026,
+   "value": 186516.55576607585,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2027,
+   "value": 187206.66695040464,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2028,
+   "value": 187955.48840495944,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2029,
+   "value": 188782.49710434675,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2030,
+   "value": 189632.02460759878,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_sick_pay",
+   "year": 2031,
+   "value": 190447.80656796694,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_sick_pay",
+   "label": "Statutory Sick Pay"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2025,
+   "value": 14081577.514007688,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2026,
+   "value": 14135088.059857488,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2027,
+   "value": 14187388.068765402,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2028,
+   "value": 14244136.843547225,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2029,
+   "value": 14306811.286181211,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2030,
+   "value": 14371192.14501977,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.ssmg",
+   "year": 2031,
+   "value": 14433015.649303794,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2025,
+   "value": 28163.155028015375,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2026,
+   "value": 28270.176119714975,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2027,
+   "value": 28374.776137530804,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2028,
+   "value": 28488.27368709445,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2029,
+   "value": 28613.622572362423,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2030,
+   "value": 28742.38429003954,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "caseloads.ssmg",
+   "year": 2031,
+   "value": 28866.031298607588,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "ssmg",
+   "label": "Sure Start Maternity Grant"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2025,
+   "value": 654447661.0694321,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2026,
+   "value": 672044090.7987709,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2027,
+   "value": 688021282.8463899,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2028,
+   "value": 704588777.7902418,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2029,
+   "value": 721842764.085712,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2030,
+   "value": 739592896.5915165,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.bsp",
+   "year": 2031,
+   "value": 757630569.6200083,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2025,
+   "value": 92227.57971167564,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2026,
+   "value": 92578.04749596119,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2027,
+   "value": 92920.58816957474,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2028,
+   "value": 93292.26550346613,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2029,
+   "value": 93702.75265604258,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2030,
+   "value": 94124.41794991493,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "caseloads.bsp",
+   "year": 2031,
+   "value": 94529.3324996233,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bsp",
+   "label": "Bereavement Support Payment"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2025,
+   "value": 563525940.8773441,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2026,
+   "value": 568299173.1681643,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2027,
+   "value": 573445937.53699,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2028,
+   "value": 585862809.08509,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2029,
+   "value": 561084451.3935778,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2030,
+   "value": 580251499.0481504,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.tax_free_childcare",
+   "year": 2031,
+   "value": 560322627.8579925,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2025,
+   "value": 974133.2423208505,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2026,
+   "value": 979682.5571617931,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2027,
+   "value": 971293.5103004575,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2028,
+   "value": 976896.6010332257,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2029,
+   "value": 957558.250394702,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2030,
+   "value": 966774.040873915,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "caseloads.tax_free_childcare",
+   "year": 2031,
+   "value": 914534.0746401399,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "tax_free_childcare",
+   "label": "Tax-Free Childcare"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2025,
+   "value": 4769443952.411871,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2026,
+   "value": 5307606110.253133,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2027,
+   "value": 5433878200.598173,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2028,
+   "value": 5575606222.716693,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2029,
+   "value": 5682980459.519588,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2030,
+   "value": 5856928114.420198,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.extended_childcare_entitlement",
+   "year": 2031,
+   "value": 5926506204.517755,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2025,
+   "value": 962176.1845641136,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2026,
+   "value": 957668.9594607353,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2027,
+   "value": 959484.9431653023,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2028,
+   "value": 963973.5987744331,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2029,
+   "value": 955768.6225590706,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2030,
+   "value": 963198.3530750275,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.extended_childcare_entitlement",
+   "year": 2031,
+   "value": 953890.9335918427,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "extended_childcare_entitlement",
+   "label": "Extended childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2025,
+   "value": 1303677004.8374069,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2026,
+   "value": 1372546985.2564154,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2027,
+   "value": 1412467299.31001,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2028,
+   "value": 1447975936.2291465,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2029,
+   "value": 1528607528.5243466,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2030,
+   "value": 1568458954.5961401,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.universal_childcare_entitlement",
+   "year": 2031,
+   "value": 1607433548.773115,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2025,
+   "value": 379484.6813406944,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2026,
+   "value": 386394.35359191895,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2027,
+   "value": 388693.47555303574,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2028,
+   "value": 390652.560110569,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2029,
+   "value": 404320.32845020294,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2030,
+   "value": 406727.4603328705,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.universal_childcare_entitlement",
+   "year": 2031,
+   "value": 408660.8797736168,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "universal_childcare_entitlement",
+   "label": "Universal childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2025,
+   "value": 443196400.7338863,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2026,
+   "value": 460006640.4923033,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2027,
+   "value": 472326964.79148394,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2028,
+   "value": 483699822.07395244,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2029,
+   "value": 495544205.88908577,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2030,
+   "value": 497331070.06473446,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.targeted_childcare_entitlement",
+   "year": 2031,
+   "value": 504378844.1796443,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2025,
+   "value": 91615.18099975586,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2026,
+   "value": 91963.32138204575,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2027,
+   "value": 92303.58706235886,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2028,
+   "value": 92672.79612493515,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2029,
+   "value": 93080.55707216263,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2030,
+   "value": 91584.69786310196,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "caseloads.targeted_childcare_entitlement",
+   "year": 2031,
+   "value": 91061.30740070343,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "targeted_childcare_entitlement",
+   "label": "Targeted childcare entitlement"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.care_to_learn",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "caseloads.care_to_learn",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "care_to_learn",
+   "label": "Care to Learn"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.childcare_grant",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "caseloads.childcare_grant",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "childcare_grant",
+   "label": "Childcare Grant"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2025,
+   "value": 200089205.6251793,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2026,
+   "value": 200849551.41910172,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2027,
+   "value": 201592698.65725708,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2028,
+   "value": 202399059.3290062,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2029,
+   "value": 203289618.08014297,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2030,
+   "value": 167103353.08280182,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.parents_learning_allowance",
+   "year": 2031,
+   "value": 167822216.12641907,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2025,
+   "value": 98858.3031744957,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2026,
+   "value": 99233.96809244156,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2027,
+   "value": 99601.13570022583,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2028,
+   "value": 99999.53524160385,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2029,
+   "value": 100439.53462457657,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2030,
+   "value": 82560.94519901276,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "caseloads.parents_learning_allowance",
+   "year": 2031,
+   "value": 82916.11468696594,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "parents_learning_allowance",
+   "label": "Parents' Learning Allowance"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2025,
+   "value": 37181344.76393461,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2026,
+   "value": 37322635.825378895,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2027,
+   "value": 37460730.62564373,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2028,
+   "value": 37610571.710464954,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2029,
+   "value": 37776058.51188898,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2030,
+   "value": 37946051.452560425,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.adult_dependants_grant",
+   "year": 2031,
+   "value": 38109291.55965805,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2025,
+   "value": 10488.390624523163,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2026,
+   "value": 10528.247059345245,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2027,
+   "value": 10567.201869010925,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2028,
+   "value": 10609.470158100128,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2029,
+   "value": 10656.151907444,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2030,
+   "value": 10704.104782104492,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "caseloads.adult_dependants_grant",
+   "year": 2031,
+   "value": 10750.152767181396,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "adult_dependants_grant",
+   "label": "Adult Dependants' Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.travel_grant",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "caseloads.travel_grant",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "travel_grant",
+   "label": "Travel Grant"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2025,
+   "value": 31398271.13342285,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2026,
+   "value": 31517584.991455078,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2027,
+   "value": 31634201.431274414,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2028,
+   "value": 31760736.053466797,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2029,
+   "value": 31900483.795166016,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2030,
+   "value": 32044037.338256836,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.disabled_students_allowance",
+   "year": 2031,
+   "value": 32181888.01574707,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2025,
+   "value": 1744.3483963012695,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2026,
+   "value": 1750.9769439697266,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2027,
+   "value": 1757.4556350708008,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2028,
+   "value": 1764.485336303711,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2029,
+   "value": 1772.2490997314453,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2030,
+   "value": 1780.2242965698242,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "caseloads.disabled_students_allowance",
+   "year": 2031,
+   "value": 1787.882667541504,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disabled_students_allowance",
+   "label": "Disabled Students' Allowance"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.bursary_fund_16_to_19",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "caseloads.bursary_fund_16_to_19",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "bursary_fund_16_to_19",
+   "label": "16 to 19 Bursary Fund"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2025,
+   "value": 205232332361.1096,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2026,
+   "value": 206012222586.4446,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2027,
+   "value": 206774471228.05975,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2028,
+   "value": 207601558499.668,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2029,
+   "value": 208515008515.17273,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2030,
+   "value": 209453332677.40167,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.nhs_spending",
+   "year": 2031,
+   "value": 210354381149.51398,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "nhs_spending",
+   "label": "NHS spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2025,
+   "value": 33304098.421608984,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2026,
+   "value": 33430655.237596173,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2027,
+   "value": 33554349.3340033,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2028,
+   "value": 33688564.45852884,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2029,
+   "value": 33836794.51014231,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2030,
+   "value": 33989060.95758362,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dfe_education_spending",
+   "year": 2031,
+   "value": 34135278.81945166,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dfe_education_spending",
+   "label": "State education spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2025,
+   "value": 25151126510.800682,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2026,
+   "value": 25246701591.88542,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2027,
+   "value": 25340114855.52831,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2028,
+   "value": 25441474019.590816,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2029,
+   "value": 25553416910.70827,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2030,
+   "value": 25668408066.936726,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.dft_subsidy_spending",
+   "year": 2031,
+   "value": 30944615266.675636,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "dft_subsidy_spending",
+   "label": "Transport subsidy spending"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.cost_of_living_support_payment",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "caseloads.cost_of_living_support_payment",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "cost_of_living_support_payment",
+   "label": "Cost-of-living support payment"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.energy_bills_rebate",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "caseloads.energy_bills_rebate",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "energy_bills_rebate",
+   "label": "Energy Bills Rebate"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.epg_subsidy",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "caseloads.epg_subsidy",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "epg_subsidy",
+   "label": "Energy Price Guarantee subsidy"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.basic_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "caseloads.basic_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "basic_income",
+   "label": "Basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.disability_basic_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "caseloads.disability_basic_income",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "disability_basic_income",
+   "label": "Disability basic income"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2025,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2026,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2027,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2028,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2029,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2030,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "spending.other_public_spending_budget_change",
+   "year": 2031,
+   "value": 0.0,
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "other_public_spending_budget_change",
+   "label": "Other public spending budget change"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2025,
+   "value": 3130000070.860857,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2026,
+   "value": 3129999934.869108,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2027,
+   "value": 3129999659.4758515,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2028,
+   "value": 3129999971.286581,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2029,
+   "value": 3129999604.8102255,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2030,
+   "value": 3129999725.6754894,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "double_counts.corporate_sdlt",
+   "year": 2031,
+   "value": 3129999838.862631,
+   "unit": "gbp",
+   "kind": "double_count",
+   "partition": null,
+   "label": "corporate_sdlt, counted again inside expected_sdlt"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2025,
+   "value": 978966763914.5134,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2026,
+   "value": 1021443831661.053,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2027,
+   "value": 1060540354380.0239,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2028,
+   "value": 1096036577748.5464,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2029,
+   "value": 1133645091567.8396,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2030,
+   "value": 1172964045336.6704,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.gov_tax",
+   "year": 2031,
+   "value": 1217259329604.8296,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2025,
+   "value": 507289555585.61816,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2026,
+   "value": 534626593895.75964,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2027,
+   "value": 560967047377.9646,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2028,
+   "value": 583794322841.5969,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2029,
+   "value": 606736767704.2439,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2030,
+   "value": 631883079371.0518,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.household_tax",
+   "year": 2031,
+   "value": 660238702302.3933,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2025,
+   "value": 499459280987.149,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2026,
+   "value": 526499323434.2302,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2027,
+   "value": 552613929618.1678,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2028,
+   "value": 574737815078.9714,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2029,
+   "value": 597441283752.3987,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2030,
+   "value": 622323704519.8606,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.pre_budget_change_household_tax",
+   "year": 2031,
+   "value": 651647666882.8048,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "pre_budget_change_household_tax"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2025,
+   "value": 538033639372.52985,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2026,
+   "value": 552208058548.4539,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2027,
+   "value": 559025643057.2411,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2028,
+   "value": 566053472893.2496,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2029,
+   "value": 574523316911.5459,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2030,
+   "value": 579305085703.9962,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.gov_spending",
+   "year": 2031,
+   "value": 589946933468.4061,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_spending"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2025,
+   "value": 538389684305.1851,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2026,
+   "value": 552578598164.1414,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2027,
+   "value": 559406220932.2922,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2028,
+   "value": 566443704502.9469,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2029,
+   "value": 574919476375.7018,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2030,
+   "value": 579709866219.54,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "model.household_benefits",
+   "year": 2031,
+   "value": 590354941802.2732,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "household_benefits"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2025,
+   "value": 975836764403.4154,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2026,
+   "value": 1018313832613.0851,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2027,
+   "value": 1057410354079.6709,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2028,
+   "value": 1092906577896.0876,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2029,
+   "value": 1130515092103.1807,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2030,
+   "value": 1169834045361.7195,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.receipts",
+   "year": 2031,
+   "value": 1214129326993.4458,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government receipts, each component once"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2025,
+   "value": 538033639676.7738,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2026,
+   "value": 552208059037.354,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2027,
+   "value": 559025643307.1086,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2028,
+   "value": 566053472435.6144,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2029,
+   "value": 574523317043.8452,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2030,
+   "value": 579305085287.3065,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.spending",
+   "year": 2031,
+   "value": 589946932722.4471,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government spending"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2025,
+   "value": 437803124726.64154,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2026,
+   "value": 466105773575.731,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2027,
+   "value": 498384710772.5623,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2028,
+   "value": 526853105460.47296,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2029,
+   "value": 555991775059.3357,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2030,
+   "value": 590528960074.4128,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.balance",
+   "year": 2031,
+   "value": 624182394270.9988,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Government balance, each receipt once"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2025,
+   "value": 551697696.1319505,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2026,
+   "value": 573788727.0823206,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2027,
+   "value": 587932937.3870641,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2028,
+   "value": 601425544.379385,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2029,
+   "value": 612524542.784497,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2030,
+   "value": 626466307.2763597,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "balance.household_only_benefits",
+   "year": 2031,
+   "value": 635100657.4934409,
+   "unit": "gbp",
+   "kind": "balance",
+   "partition": null,
+   "label": "Benefits in household_benefits but not in gov_spending"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2025,
+   "value": 440933124873.35913,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2026,
+   "value": 469235773431.7386,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2027,
+   "value": 501514711424.7265,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2028,
+   "value": 529983106859.2174,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2029,
+   "value": 559121775135.3358,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2030,
+   "value": 593658959431.4342,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "model.gov_balance",
+   "year": 2031,
+   "value": 627312396103.4205,
+   "unit": "gbp",
+   "kind": "model_total",
+   "partition": null,
+   "label": "gov_balance"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2025,
+   "value": 1671225658932.162,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2026,
+   "value": 1733933903918.711,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2027,
+   "value": 1786792811393.0068,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2028,
+   "value": 1837490253867.1548,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2029,
+   "value": 1899443273442.607,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2030,
+   "value": 1958070419692.7725,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_market_income",
+   "year": 2031,
+   "value": 2030307938225.9048,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household market income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2025,
+   "value": 1662845456756.1794,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2026,
+   "value": 1710908123095.9045,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2027,
+   "value": 1743115474011.6213,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2028,
+   "value": 1776966674392.025,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2029,
+   "value": 1812648751541.618,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2030,
+   "value": 1849604189724.0015,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.household_net_income",
+   "year": 2031,
+   "value": 1901814852667.9023,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2025,
+   "value": 1477497599801.4927,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2026,
+   "value": 1524365447451.7742,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2027,
+   "value": 1557424708805.0208,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2028,
+   "value": 1590631579327.68,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2029,
+   "value": 1624770529416.2014,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2030,
+   "value": 1659800503787.3513,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "household.hbai_household_net_income",
+   "year": 2031,
+   "value": 1706265955643.35,
+   "unit": "gbp",
+   "kind": "household_total",
+   "partition": null,
+   "label": "Household net income (HBAI definition)"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2025,
+   "value": 0.15790499791115192,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2026,
+   "value": 0.15015054717546153,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2027,
+   "value": 0.1549582355031067,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2028,
+   "value": 0.15586605016301394,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2029,
+   "value": 0.15679856209322698,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2030,
+   "value": 0.15996963062767566,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.all",
+   "year": 2031,
+   "value": 0.15916276272552643,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2025,
+   "value": 11008006.535612345,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2026,
+   "value": 10507198.299471915,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2027,
+   "value": 10883751.14921306,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2028,
+   "value": 10991302.525305092,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2029,
+   "value": 11105712.280909285,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2030,
+   "value": 11381299.168434069,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.all",
+   "year": 2031,
+   "value": 11372607.559264764,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2025,
+   "value": 0.23024237894583952,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2026,
+   "value": 0.20587063573611564,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2027,
+   "value": 0.21312205523439626,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2028,
+   "value": 0.21148974274821794,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2029,
+   "value": 0.2129381736428246,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2030,
+   "value": 0.2171366623415043,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.children",
+   "year": 2031,
+   "value": 0.2168645562087503,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2025,
+   "value": 3458586.670649603,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2026,
+   "value": 3104238.0042080134,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2027,
+   "value": 3225469.4537050426,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2028,
+   "value": 3213568.3187645674,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2029,
+   "value": 3249813.6879644096,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2030,
+   "value": 3328802.6769966334,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.children",
+   "year": 2031,
+   "value": 3338933.418882489,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2025,
+   "value": 0.13730515589263637,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2026,
+   "value": 0.13444889083444914,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2027,
+   "value": 0.13964335698946462,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2028,
+   "value": 0.14095635404241666,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2029,
+   "value": 0.14196947141222863,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2030,
+   "value": 0.1453637344339517,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.working_age_adults",
+   "year": 2031,
+   "value": 0.1424988521749652,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2025,
+   "value": 5861346.487035349,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2026,
+   "value": 5780330.343414247,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2027,
+   "value": 6067671.953066379,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2028,
+   "value": 6169748.167899072,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2029,
+   "value": 6241435.053964257,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2030,
+   "value": 6419415.955847114,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.working_age_adults",
+   "year": 2031,
+   "value": 6319971.187485427,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2025,
+   "value": 0.14063908804109557,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2026,
+   "value": 0.13628217188144012,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2027,
+   "value": 0.1365202033742876,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2028,
+   "value": 0.1391945511558675,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2029,
+   "value": 0.1391430413120495,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2030,
+   "value": 0.14011702215368302,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_bhc.pensioners",
+   "year": 2031,
+   "value": 0.14640454331430913,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2025,
+   "value": 1688073.3779273927,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2026,
+   "value": 1622629.9518496543,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2027,
+   "value": 1590609.7424416393,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2028,
+   "value": 1607986.0386414528,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2029,
+   "value": 1614463.5389806181,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2030,
+   "value": 1633080.5355903208,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_bhc.pensioners",
+   "year": 2031,
+   "value": 1713702.9528968483,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2025,
+   "value": 0.2084922594723321,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2026,
+   "value": 0.2033983080431449,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2027,
+   "value": 0.2085258023862174,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2028,
+   "value": 0.21083623822359046,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2029,
+   "value": 0.21373904608988534,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2030,
+   "value": 0.2213187707909106,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.all",
+   "year": 2031,
+   "value": 0.2195671141063277,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2025,
+   "value": 14534588.42504394,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2026,
+   "value": 14233357.097853199,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2027,
+   "value": 14646158.908514857,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2028,
+   "value": 14867669.227449715,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2029,
+   "value": 15138686.971242383,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2030,
+   "value": 15746083.378938913,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.all",
+   "year": 2031,
+   "value": 15688660.958704859,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2025,
+   "value": 0.31720685844300495,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2026,
+   "value": 0.30038158814530413,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2027,
+   "value": 0.3065600330656107,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2028,
+   "value": 0.3089024392477794,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2029,
+   "value": 0.3131465359163617,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2030,
+   "value": 0.32764715169339104,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.children",
+   "year": 2031,
+   "value": 0.32587820140005935,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2025,
+   "value": 4764923.892259136,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2026,
+   "value": 4529329.490584716,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2027,
+   "value": 4639595.002462,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2028,
+   "value": 4693745.802781373,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2029,
+   "value": 4779170.786289513,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2030,
+   "value": 5022978.173772946,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.children",
+   "year": 2031,
+   "value": 5017351.0884489715,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2025,
+   "value": 0.19375179335562778,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2026,
+   "value": 0.1915301826384273,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2027,
+   "value": 0.19779351466886932,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2028,
+   "value": 0.19985745387449372,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2029,
+   "value": 0.20299186364561206,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2030,
+   "value": 0.21009860237041597,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.working_age_adults",
+   "year": 2031,
+   "value": 0.205233615867211,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2025,
+   "value": 8270966.854513526,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2026,
+   "value": 8234413.236980796,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2027,
+   "value": 8594366.300899416,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2028,
+   "value": 8747886.310340255,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2029,
+   "value": 8924175.886719018,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2030,
+   "value": 9278176.056839228,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.working_age_adults",
+   "year": 2031,
+   "value": 9102322.714793772,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2025,
+   "value": 0.1248615596202156,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2026,
+   "value": 0.12343063061462466,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2027,
+   "value": 0.12120729498631465,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2028,
+   "value": 0.12344422855077232,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2029,
+   "value": 0.12370524920005636,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2030,
+   "value": 0.12397378149719714,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.absolute_ahc.pensioners",
+   "year": 2031,
+   "value": 0.13404122784123754,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2025,
+   "value": 1498697.6782712787,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2026,
+   "value": 1469614.3702876866,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2027,
+   "value": 1412197.6051534414,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2028,
+   "value": 1426037.1143280864,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2029,
+   "value": 1435340.2982338518,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2030,
+   "value": 1444929.1483267397,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.absolute_ahc.pensioners",
+   "year": 2031,
+   "value": 1568987.155462116,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Absolute poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2025,
+   "value": 0.17062007668867718,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2026,
+   "value": 0.1647051950949729,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2027,
+   "value": 0.1644876206126917,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2028,
+   "value": 0.16684150829295824,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2029,
+   "value": 0.1684367435335271,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2030,
+   "value": 0.1631533914075491,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.all",
+   "year": 2031,
+   "value": 0.169943728112801,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2025,
+   "value": 11894410.842856497,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2026,
+   "value": 11525699.895011187,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2027,
+   "value": 11553063.469406977,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2028,
+   "value": 11765265.684914708,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2029,
+   "value": 11930020.187968686,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2030,
+   "value": 11607812.999679968,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.all",
+   "year": 2031,
+   "value": 12142936.53797774,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2025,
+   "value": 0.25579913589553366,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2026,
+   "value": 0.23345621726435167,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2027,
+   "value": 0.22912843225646004,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2028,
+   "value": 0.23084457664090657,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2029,
+   "value": 0.23197251050977175,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2030,
+   "value": 0.2220824501863291,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.children",
+   "year": 2031,
+   "value": 0.23445025294767866,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2025,
+   "value": 3842487.581228867,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2026,
+   "value": 3520189.556705728,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2027,
+   "value": 3467715.9921610057,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2028,
+   "value": 3507663.3429688513,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2029,
+   "value": 3540311.3823575675,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2030,
+   "value": 3404623.8287089914,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.children",
+   "year": 2031,
+   "value": 3609689.837369889,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2025,
+   "value": 0.14589881032453236,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2026,
+   "value": 0.14416151943670144,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2027,
+   "value": 0.1465298878616869,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2028,
+   "value": 0.14949165839067746,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2029,
+   "value": 0.15186122947304564,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2030,
+   "value": 0.14784727703111472,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.working_age_adults",
+   "year": 2031,
+   "value": 0.15069757220037083,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2025,
+   "value": 6228196.412573293,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2026,
+   "value": 6197903.1584480405,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2027,
+   "value": 6366900.008937746,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2028,
+   "value": 6543343.801262975,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2029,
+   "value": 6676308.586224228,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2030,
+   "value": 6529091.818519026,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.working_age_adults",
+   "year": 2031,
+   "value": 6683592.883688301,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2025,
+   "value": 0.15194083636457575,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2026,
+   "value": 0.15181812223954255,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2027,
+   "value": 0.1474923682419708,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2028,
+   "value": 0.14839398004790294,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2029,
+   "value": 0.1476699298274378,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2030,
+   "value": 0.14363623269573814,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_bhc.pensioners",
+   "year": 2031,
+   "value": 0.1580190556933559,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2025,
+   "value": 1823726.8490543365,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2026,
+   "value": 1807607.179857418,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2027,
+   "value": 1718447.4683082253,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2028,
+   "value": 1714258.540682882,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2029,
+   "value": 1713400.2193868905,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2030,
+   "value": 1674097.3524519503,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_bhc.pensioners",
+   "year": 2031,
+   "value": 1849653.8169195503,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, before housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2025,
+   "value": 0.21330212332422502,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2026,
+   "value": 0.2105464759711648,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2027,
+   "value": 0.21119415618195903,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2028,
+   "value": 0.2124423499774284,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2029,
+   "value": 0.2140000786845929,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2030,
+   "value": 0.2204001169903213,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.all",
+   "year": 2031,
+   "value": 0.2194456696036841,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2025,
+   "value": 14869897.714917302,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2026,
+   "value": 14733569.846394584,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2027,
+   "value": 14833575.205535918,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2028,
+   "value": 14980928.401961535,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2029,
+   "value": 15157175.360766247,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2030,
+   "value": 15680724.262363464,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.all",
+   "year": 2031,
+   "value": 15679983.42229405,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: everyone"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2025,
+   "value": 0.3248406624741081,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2026,
+   "value": 0.3131278902007049,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2027,
+   "value": 0.30979319184398263,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2028,
+   "value": 0.3102686929501225,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2029,
+   "value": 0.3134903767691043,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2030,
+   "value": 0.3252235647703323,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.children",
+   "year": 2031,
+   "value": 0.3257920669222945,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2025,
+   "value": 4879595.105218306,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2026,
+   "value": 4721525.697256014,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2027,
+   "value": 4688526.845143169,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2028,
+   "value": 4714505.909423858,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2029,
+   "value": 4784418.406716645,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2030,
+   "value": 4985823.496389523,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.children",
+   "year": 2031,
+   "value": 5016024.927589148,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: children"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2025,
+   "value": 0.19713460206621386,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2026,
+   "value": 0.19751408902821108,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2027,
+   "value": 0.19980334977328973,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2028,
+   "value": 0.20092494834158509,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2029,
+   "value": 0.20323204364702235,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2030,
+   "value": 0.2095568415310035,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.working_age_adults",
+   "year": 2031,
+   "value": 0.2051403722499053,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2025,
+   "value": 8415373.769339144,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2026,
+   "value": 8491677.952683121,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2027,
+   "value": 8681696.055470556,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2028,
+   "value": 8794611.213785172,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2029,
+   "value": 8934734.972874314,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2030,
+   "value": 9254251.326298147,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.working_age_adults",
+   "year": 2031,
+   "value": 9098187.264116138,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: working-age adults"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2025,
+   "value": 0.1312126349091424,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2026,
+   "value": 0.12769319774473814,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2027,
+   "value": 0.12559784398751747,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2028,
+   "value": 0.12740664745148308,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2029,
+   "value": 0.12393637087688392,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2030,
+   "value": 0.1236065858698001,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty.relative_ahc.pensioners",
+   "year": 2031,
+   "value": 0.13376648593709345,
+   "unit": "rate",
+   "kind": "poverty",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2025,
+   "value": 1574928.8403598517,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2026,
+   "value": 1520366.1964554489,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2027,
+   "value": 1463352.3049221933,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2028,
+   "value": 1471811.2787525058,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2029,
+   "value": 1438021.9811752886,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2030,
+   "value": 1440649.439675793,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "poverty_count.relative_ahc.pensioners",
+   "year": 2031,
+   "value": 1565771.230588764,
+   "unit": "count",
+   "kind": "poverty_count",
+   "partition": null,
+   "label": "Relative poverty, after housing costs: pensioners"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2025,
+   "value": 0.31169660677586286,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2026,
+   "value": 0.3094015441232131,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2027,
+   "value": 0.3105687571293162,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2028,
+   "value": 0.3112819865588672,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2029,
+   "value": 0.31188628846609523,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2030,
+   "value": 0.3137188460113969,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "inequality.gini_equiv_hbai_bhc",
+   "year": 2031,
+   "value": 0.3126616094414172,
+   "unit": "index",
+   "kind": "inequality",
+   "partition": null,
+   "label": "Gini coefficient, equivalised HBAI income before housing costs"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2025,
+   "value": 18262.585926938675,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2026,
+   "value": 18565.573452097553,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2027,
+   "value": 18587.9409768735,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2028,
+   "value": 18712.32311277851,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2029,
+   "value": 19079.33376464379,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2030,
+   "value": 19168.884477875916,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.1",
+   "year": 2031,
+   "value": 19487.832363597438,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 1: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2025,
+   "value": 28212.59715391376,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2026,
+   "value": 29005.91280891695,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2027,
+   "value": 28622.542707465953,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2028,
+   "value": 28878.39944749893,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2029,
+   "value": 29211.074914268487,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2030,
+   "value": 29528.185297717675,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.2",
+   "year": 2031,
+   "value": 30103.165466505827,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 2: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2025,
+   "value": 34413.19157264763,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2026,
+   "value": 35673.03127903994,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2027,
+   "value": 36287.079062372846,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2028,
+   "value": 36891.915260352755,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2029,
+   "value": 37204.02706843331,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2030,
+   "value": 37191.52316634799,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.3",
+   "year": 2031,
+   "value": 37443.87462441918,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 3: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2025,
+   "value": 37642.82250138588,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2026,
+   "value": 39339.82023962752,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2027,
+   "value": 40283.78733924495,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2028,
+   "value": 41009.69588636075,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2029,
+   "value": 41559.21709716546,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2030,
+   "value": 42169.73199175639,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.4",
+   "year": 2031,
+   "value": 43752.63830672907,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 4: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2025,
+   "value": 45171.99281201596,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2026,
+   "value": 46058.866814268324,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2027,
+   "value": 46923.63741254213,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2028,
+   "value": 47337.90189430204,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2029,
+   "value": 48018.33585686029,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2030,
+   "value": 48015.10342326575,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.5",
+   "year": 2031,
+   "value": 49372.799605199805,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 5: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2025,
+   "value": 48820.920957344184,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2026,
+   "value": 50247.0931869786,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2027,
+   "value": 51421.09655308313,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2028,
+   "value": 52276.76979311605,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2029,
+   "value": 52861.797979942385,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2030,
+   "value": 54632.18051219701,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.6",
+   "year": 2031,
+   "value": 56251.724813561,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 6: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2025,
+   "value": 55387.77506364148,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2026,
+   "value": 56756.00462516803,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2027,
+   "value": 57200.40880691023,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2028,
+   "value": 58134.97463181802,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2029,
+   "value": 58986.25591531483,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2030,
+   "value": 60251.89005484455,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.7",
+   "year": 2031,
+   "value": 62408.99721436145,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 7: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2025,
+   "value": 70806.00916651895,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2026,
+   "value": 72028.31133150091,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2027,
+   "value": 73225.66554327721,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2028,
+   "value": 74341.65681045009,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2029,
+   "value": 75651.30440928646,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2030,
+   "value": 76728.81669615183,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.8",
+   "year": 2031,
+   "value": 77557.30506779443,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 8: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2025,
+   "value": 78613.5574256512,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2026,
+   "value": 80276.59014426098,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2027,
+   "value": 81556.99374054834,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2028,
+   "value": 83394.03807203949,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2029,
+   "value": 84834.09750237051,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2030,
+   "value": 86472.88055967825,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.9",
+   "year": 2031,
+   "value": 90591.67357463166,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 9: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2025,
+   "value": 121628.70831615487,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2026,
+   "value": 124668.9979412319,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2027,
+   "value": 125904.42260266874,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2028,
+   "value": 128224.60518010141,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2029,
+   "value": 130772.6528624675,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2030,
+   "value": 133647.48170630506,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "deciles.mean_income.10",
+   "year": 2031,
+   "value": 135669.54991935962,
+   "unit": "gbp_household",
+   "kind": "decile",
+   "partition": null,
+   "label": "Decile 10: mean household_net_income per household"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2025,
+   "value": 6231978976.779907,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2026,
+   "value": 6514784443.9122925,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2027,
+   "value": 6724056114.445618,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2028,
+   "value": 6921661403.251404,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2029,
+   "value": 7132082771.443726,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2030,
+   "value": 7370366483.297607,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.basic_rate_plus_1pp",
+   "year": 2031,
+   "value": 7650165153.850464,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise basic rate by 1pp"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2025,
+   "value": 6375058856.060486,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2026,
+   "value": 6667124628.2039795,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2027,
+   "value": 6885617422.428345,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2028,
+   "value": 7091326778.457153,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2029,
+   "value": 7306154419.062439,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2030,
+   "value": 7546544692.554932,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.basic_rate_plus_1pp",
+   "year": 2031,
+   "value": 7822055582.338684,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise basic rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2025,
+   "value": 3666986552.897339,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2026,
+   "value": 3977030845.7789307,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2027,
+   "value": 4223083637.6138306,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2028,
+   "value": 4369415244.928589,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2029,
+   "value": 4609416868.0217285,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2030,
+   "value": 4888880522.356812,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reforms.higher_rate_plus_1pp",
+   "year": 2031,
+   "value": 5111936398.052734,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise higher rate by 1pp"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2025,
+   "value": 3671386650.1765137,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2026,
+   "value": 3982920392.3969727,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2027,
+   "value": 4229920079.0026245,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2028,
+   "value": 4377131336.593445,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2029,
+   "value": 4618077924.957153,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2030,
+   "value": 4898722761.492981,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.higher_rate_plus_1pp",
+   "year": 2031,
+   "value": 5122219947.487732,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise higher rate by 1pp: change in income_tax"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2025,
+   "value": -3823707824.9178467,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2026,
+   "value": -3938856676.534912,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2027,
+   "value": -4026654105.0057983,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2028,
+   "value": -4071413798.9171143,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2029,
+   "value": -4134957766.1256104,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2030,
+   "value": -4229688107.533081,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reforms.personal_allowance_13000",
+   "year": 2031,
+   "value": -1711397144.4260254,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2025,
+   "value": -3955109908.810852,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2026,
+   "value": -4086527957.4680176,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2027,
+   "value": -4183341947.9663086,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2028,
+   "value": -4230614997.3900757,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2029,
+   "value": -4295011805.698914,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2030,
+   "value": -4392504289.538818,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.personal_allowance_13000",
+   "year": 2031,
+   "value": -1765597207.2024536,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise personal allowance by ~800GBP/year: change in income_tax"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2025,
+   "value": -1977222467.3527832,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2026,
+   "value": -1744958365.3483887,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2027,
+   "value": -1629814465.277588,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2028,
+   "value": -1534763674.378479,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2029,
+   "value": -1428204556.7736816,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2030,
+   "value": -1322075255.131958,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reforms.child_benefit_additional_25",
+   "year": 2031,
+   "value": -1215395543.2149658,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2025,
+   "value": 2332987565.3313274,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2026,
+   "value": 2143319353.6422234,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2027,
+   "value": 2025631616.9500465,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2028,
+   "value": 1921833405.853962,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2029,
+   "value": 1815708316.6814766,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2030,
+   "value": 1706257920.2213326,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reform_targets.child_benefit_additional_25",
+   "year": 2031,
+   "value": 1592582974.3537292,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise child benefit by 25GBP/week per additional child: change in child_benefit"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2025,
+   "value": -19987138619.665894,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2026,
+   "value": -20585697292.380737,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2027,
+   "value": -20867244208.72113,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2028,
+   "value": -21212204041.55127,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2029,
+   "value": -21266028636.272034,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2030,
+   "value": -21323353884.143677,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reforms.uc_taper_20pc",
+   "year": 2031,
+   "value": -21417216822.362915,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2025,
+   "value": 20026032932.944794,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2026,
+   "value": 20623599493.57924,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2027,
+   "value": 20905978230.628372,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2028,
+   "value": 21252138646.154373,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2029,
+   "value": 21307648843.63382,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2030,
+   "value": 21364495790.550797,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_taper_20pc",
+   "year": 2031,
+   "value": 21460406654.06598,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Reduce Universal Credit taper rate to 20%: change in universal_credit"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2025,
+   "value": 11191545342.31836,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2026,
+   "value": 11645153494.695984,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2027,
+   "value": 11972824309.717712,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2028,
+   "value": 12257716047.155273,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2029,
+   "value": 12566231791.670166,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2030,
+   "value": 12912911611.737793,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reforms.employee_nics_main_10pc",
+   "year": 2031,
+   "value": 13392154732.762207,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2025,
+   "value": 11458770099.1045,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2026,
+   "value": 11919342691.629387,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2027,
+   "value": 12255153227.885277,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2028,
+   "value": 12566120848.304436,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2029,
+   "value": 12878237799.178757,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2030,
+   "value": 13226533370.28511,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reform_targets.employee_nics_main_10pc",
+   "year": 2031,
+   "value": 13713984420.560326,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise Class 1 main employee NICs rate to 10%: change in national_insurance"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2025,
+   "value": 31259132637.84729,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2026,
+   "value": 32099610265.377075,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2027,
+   "value": 32862745005.17981,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2028,
+   "value": 33654079646.918335,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2029,
+   "value": 34478200723.7262,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2030,
+   "value": 35326019624.22656,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reforms.vat_standard_plus_2pp",
+   "year": 2031,
+   "value": 36187574723.726685,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2025,
+   "value": 31259131903.187378,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2026,
+   "value": 32099610338.78839,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2027,
+   "value": 32862746112.62982,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2028,
+   "value": 33654077425.53827,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2029,
+   "value": 34478201429.00751,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2030,
+   "value": 35326020466.349304,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reform_targets.vat_standard_plus_2pp",
+   "year": 2031,
+   "value": 36187575185.13623,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise VAT standard rate by 2pp: change in vat"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2025,
+   "value": 2825467413.079834,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2026,
+   "value": 3049458999.274414,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2027,
+   "value": 3238599613.133667,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2028,
+   "value": 3549931915.0806885,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2029,
+   "value": 3756212324.8634033,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2030,
+   "value": 3997750150.373169,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reforms.additional_rate_plus_3pp",
+   "year": 2031,
+   "value": 4332961887.065674,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise additional rate by 3pp"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2025,
+   "value": 2825466843.0894775,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2026,
+   "value": 3049458483.8516235,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2027,
+   "value": 3238600146.871582,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2028,
+   "value": 3549931957.5039062,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2029,
+   "value": 3756211982.0652466,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2030,
+   "value": 3997750696.064453,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reform_targets.additional_rate_plus_3pp",
+   "year": 2031,
+   "value": 4332963129.139282,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise additional rate by 3pp: change in income_tax"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2025,
+   "value": -3024426671.0059814,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2026,
+   "value": -3159166047.906311,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2027,
+   "value": -3213933471.489624,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2028,
+   "value": -3272574045.103821,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2029,
+   "value": -3304278267.8723145,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2030,
+   "value": -3329443110.629883,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reforms.uc_standard_allowance_plus_10pc",
+   "year": 2031,
+   "value": -3364831042.0513916,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2025,
+   "value": 3028001830.553894,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2026,
+   "value": 3162547160.014694,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2027,
+   "value": 3218303161.6876984,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2028,
+   "value": 3277244745.4717865,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2029,
+   "value": 3309693715.520218,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2030,
+   "value": 3335295107.935898,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
+   "year": 2031,
+   "value": 3368860316.26828,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the Universal Credit standard allowance by 10%: change in universal_credit"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2025,
+   "value": -9035141432.653503,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2026,
+   "value": -9262484295.463745,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2027,
+   "value": -9298804936.553955,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2028,
+   "value": -9371209948.825623,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2029,
+   "value": -9561709368.57013,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2030,
+   "value": -9807065305.57251,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reforms.state_pension_plus_10pc",
+   "year": 2031,
+   "value": -10306378596.512695,
+   "unit": "gbp",
+   "kind": "reform",
+   "partition": null,
+   "label": "Raise the State Pension by 10%"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2025,
+   "value": 12360890321.875732,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2026,
+   "value": 12831378854.052383,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2027,
+   "value": 13012698482.677444,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2028,
+   "value": 13223877715.22789,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2029,
+   "value": 13614122674.000916,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2030,
+   "value": 14017293680.398499,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  },
+  {
+   "metric_id": "reform_targets.state_pension_plus_10pc",
+   "year": 2031,
+   "value": 14429529140.882904,
+   "unit": "gbp",
+   "kind": "reform_target",
+   "partition": null,
+   "label": "Raise the State Pension by 10%: change in state_pension"
+  }
+ ],
+ "identities": [
+  {
+   "identity_id": "closure",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "weights:person",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "weights:benunit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "weights:household",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:income_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:income_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:income_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:nics_individual",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:nics_individual",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:nics_individual",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:nics_employer",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:nics_employer",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:nics_employer",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:employer_nics_response_capital",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:employer_nics_response_consumer",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:capital_gains_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:capital_gains_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:capital_gains_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:student_loan_repayments",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:student_loan_repayments",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:student_loan_repayments",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:vat",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:vat",
+   "year": null,
+   "status": "fail",
+   "severity": "fail",
+   "detail": "2025-26: 76 units below zero, a weighted \u00a3-69,996,281 in total; 2026-27: 76 units below zero, a weighted \u00a3-71,878,301 in total; 2027-28: 76 units below zero, a weighted \u00a3-73,587,136 in total; 2028-29: 76 units below zero, a weighted \u00a3-75,359,106 in total; 2029-30: 76 units below zero, a weighted \u00a3-77,204,504 in total; 2030-31: 76 units below zero, a weighted \u00a3-79,102,963 in total; 2031-32: 76 units below zero, a weighted \u00a3-81,032,183 in total"
+  },
+  {
+   "identity_id": "inert:vat",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:vat_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:private_school_vat",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:private_school_vat",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:fuel_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:fuel_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:fuel_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:alcohol_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:alcohol_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:alcohol_duty",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:tobacco_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:tobacco_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:tobacco_duty",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:vehicle_excise_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:vehicle_excise_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:vehicle_excise_duty",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:tv_licence",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:tv_licence",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:tv_licence",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:council_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:council_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:council_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:high_value_council_tax_surcharge",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:high_value_council_tax_surcharge",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:high_value_council_tax_surcharge",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit"
+  },
+  {
+   "identity_id": "finite:domestic_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:domestic_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:domestic_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:business_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:business_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:business_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:sdlt_household",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:sdlt_household",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:sdlt_household",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:land_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:land_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:land_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:land_and_buildings_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:land_and_buildings_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:land_and_buildings_transaction_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:corporate_incident_tax_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:consumer_incident_tax_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:non_primary_residence_wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:non_primary_residence_wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:land_value_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:land_value_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:carbon_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:carbon_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:state_pension",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:state_pension",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:state_pension",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:pension_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:pension_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:pension_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:winter_fuel_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:winter_fuel_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:winter_fuel_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:pawhp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:pawhp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:pawhp",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:universal_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:universal_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:universal_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:housing_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:housing_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:housing_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:council_tax_reduction",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:council_tax_reduction",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:council_tax_reduction",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:esa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:esa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:esa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:esa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:esa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:esa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:jsa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:jsa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:jsa_income",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:jsa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:jsa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:jsa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:income_support",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:income_support",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:income_support",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:working_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:working_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:working_tax_credit",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:child_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:child_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:child_tax_credit",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:incapacity_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:incapacity_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:incapacity_benefit",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:pip",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:pip",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:pip",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:dla",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:dla",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:dla",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:attendance_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:attendance_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:attendance_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:carers_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:carers_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:carers_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:carer_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:carer_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:carer_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:scottish_carer_supplement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:scottish_carer_supplement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:scottish_carer_supplement",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit"
+  },
+  {
+   "identity_id": "finite:sda",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:sda",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:sda",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:iidb",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:iidb",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:iidb",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:afcs",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:afcs",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:afcs",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:child_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:child_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:child_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:scottish_child_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:scottish_child_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:scottish_child_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:two_child_limit_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:two_child_limit_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:healthy_start_vouchers",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:healthy_start_vouchers",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:healthy_start_vouchers",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:maternity_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:maternity_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:maternity_allowance",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:statutory_maternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:statutory_maternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:statutory_maternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:statutory_sick_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:statutory_sick_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:statutory_sick_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:ssmg",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:ssmg",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:ssmg",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:bsp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:bsp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:bsp",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:tax_free_childcare",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:tax_free_childcare",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:tax_free_childcare",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:extended_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:extended_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:extended_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:universal_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:universal_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:universal_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:targeted_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:targeted_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:targeted_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:care_to_learn",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:care_to_learn",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:care_to_learn",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:childcare_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:childcare_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:childcare_grant",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:parents_learning_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:parents_learning_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:parents_learning_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:adult_dependants_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:adult_dependants_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:adult_dependants_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:travel_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:travel_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:travel_grant",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:disabled_students_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:disabled_students_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:disabled_students_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:bursary_fund_16_to_19",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:bursary_fund_16_to_19",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:bursary_fund_16_to_19",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
+  {
+   "identity_id": "finite:nhs_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:nhs_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:nhs_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:dfe_education_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:dfe_education_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:dfe_education_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:dft_subsidy_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:dft_subsidy_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:dft_subsidy_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:cost_of_living_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:cost_of_living_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:energy_bills_rebate",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:energy_bills_rebate",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:epg_subsidy",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:epg_subsidy",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:basic_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:disability_basic_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:other_public_spending_budget_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "overlap_guard:property_transaction_tax_geography",
+   "year": null,
+   "status": "fail",
+   "severity": "fail",
+   "detail": "2025-26: 86 households have more than one, a weighted 39,273; 2026-27: 86 households have more than one, a weighted 39,422; 2027-28: 88 households have more than one, a weighted 39,718; 2028-29: 92 households have more than one, a weighted 40,335; 2029-30: 94 households have more than one, a weighted 40,724; 2030-31: 96 households have more than one, a weighted 41,410; 2031-32: 104 households have more than one, a weighted 42,213"
+  },
+  {
+   "identity_id": "overlap_guard:local_tax_geography",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:gov_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:household_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:pre_budget_change_household_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:gov_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:household_benefits",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:gov_balance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "identity:household_net_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:absolute_bhc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "bounds:poverty_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:children",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:working_age_adults",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:pensioners",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:absolute_ahc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:relative_bhc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "available:relative_ahc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:income_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:national_insurance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:ni_employer",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:employer_ni_response_capital_incidence",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:employer_ni_response_consumer_incidence",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:capital_gains_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:student_loan_repayments",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:vat",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:vat_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:private_school_vat",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:fuel_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:alcohol_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:tobacco_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:vehicle_excise_duty",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:tv_licence",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:council_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:high_value_council_tax_surcharge",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:domestic_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:business_rates",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:expected_sdlt",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:expected_ltt",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:expected_lbtt",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:corporate_incident_tax_revenue_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:consumer_incident_tax_revenue_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:non_primary_residence_wealth_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:LVT",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:carbon_tax",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:state_pension",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:pension_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:winter_fuel_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:pawhp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:universal_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:housing_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:council_tax_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:esa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:esa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:jsa_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:jsa_contrib",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:income_support",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:working_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:child_tax_credit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:incapacity_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:pip",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:dla",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:attendance_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:carers_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:carer_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:scottish_carer_supplement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:sda",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:iidb",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:afcs",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:child_benefit",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:scottish_child_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:two_child_limit_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:healthy_start_vouchers",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:maternity_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:statutory_maternity_pay",
+   "year": null,
+   "status": "fail",
+   "severity": "fail",
+   "detail": "gov_spending: universal_credit rises by 0.0068 per unit of statutory_maternity_pay; household_benefits: universal_credit rises by 0.0068 per unit of statutory_maternity_pay"
+  },
+  {
+   "identity_id": "counted_once:statutory_sick_pay",
+   "year": null,
+   "status": "fail",
+   "severity": "fail",
+   "detail": "gov_spending: universal_credit rises by 0.0099 per unit of statutory_sick_pay; household_benefits: universal_credit rises by 0.0099 per unit of statutory_sick_pay"
+  },
+  {
+   "identity_id": "counted_once:ssmg",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:bsp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:tax_free_childcare",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:extended_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:universal_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:targeted_childcare_entitlement",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:care_to_learn",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:childcare_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:parents_learning_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:adult_dependants_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:travel_grant",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:disabled_students_allowance",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:bursary_fund_16_to_19",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:nhs_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:dfe_education_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:dft_subsidy_spending",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:cost_of_living_support_payment",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:energy_bills_rebate",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:epg_subsidy",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:basic_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:disability_basic_income",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:other_public_spending_budget_change",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:corporate_sdlt",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "double_count_present:corporate_sdlt",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:reset_reproduces_baseline",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:ran",
+   "year": null,
+   "status": "pass",
+   "severity": "warn",
+   "detail": ""
+  },
+  {
+   "identity_id": "determinism:rebuilt_baseline",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:basic_rate_plus_1pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:higher_rate_plus_1pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:personal_allowance_13000",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:child_benefit_additional_25",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:uc_taper_20pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:employee_nics_main_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:vat_standard_plus_2pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:additional_rate_plus_3pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:uc_standard_allowance_plus_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "responsive:state_pension_plus_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:basic_rate_plus_1pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:higher_rate_plus_1pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:personal_allowance_13000",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:child_benefit_additional_25",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:uc_taper_20pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:employee_nics_main_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:vat_standard_plus_2pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:additional_rate_plus_3pp",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:uc_standard_allowance_plus_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "reform_runs:state_pension_plus_10pc",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  },
+  {
+   "identity_id": "finite:metrics",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "detail": ""
+  }
+ ]
+}
\ No newline at end of file
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 36ca3fb7..f67926bd 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1472,6 +1472,91 @@ def test_responsiveness_is_monotone_in_the_size_of_the_response(low, high):
     assert (stronger == "pass") == (high >= 1.0)
 
 
+REAL_REPORT = (
+    Path(__file__).parent / "fixtures" / "uk_metrics" / "budget_metrics_report.json"
+)
+
+
+def _real_report():
+    return json.loads(REAL_REPORT.read_text())
+
+
+def test_the_real_report_on_the_certified_data_passes_responsiveness():
+    """W3's real report: ten reforms, each clearing its minimum in every year."""
+
+    report = _real_report()
+    result, evidence = reform_responsiveness_gate(report)
+    assert result.status == "pass", result.summary
+    assert "All 10 standard reforms" in result.summary
+    rows = {row["id"]: row for row in evidence["reforms"]}
+    uc = rows["uc_standard_allowance_plus_10pc"]["target_changes"]
+    pension = rows["state_pension_plus_10pc"]["target_changes"]
+    assert all(3.0e9 < value < 3.4e9 for value in uc.values())
+    assert all(12.3e9 < value < 14.5e9 for value in pension.values())
+
+
+def reform_responsiveness_gate(report):
+    from policyengine.provenance.uk_candidate import reform_responsiveness
+
+    return reform_responsiveness(
+        report=report, standard_reforms=_standard_reforms(), years=RESPONSE_YEARS
+    )
+
+
+@pytest.mark.parametrize("reform_id", [UC_ALLOWANCE, STATE_PENSION])
+def test_the_backtest_failures_fail_on_the_real_report(reform_id):
+    """Nikhil's backtest: UC allowance +10% returned exactly £0; State Pension +10% barely moved."""
+
+    report = _real_report()
+    for row in report["metrics"]:
+        if row["metric_id"] == f"reform_targets.{reform_id}":
+            row["value"] = 0.0 if reform_id == UC_ALLOWANCE else row["value"] * 0.01
+    # The tool's own check would say fail; a report that still says pass is an error.
+    assert reform_responsiveness_gate(report)[0].status == "error"
+    for row in report["identities"]:
+        if row["identity_id"] == f"responsive:{reform_id}":
+            row["status"] = "fail"
+            row["detail"] = "did not move"
+    result = reform_responsiveness_gate(report)[0]
+    assert result.status == "fail"
+    assert f"({reform_id}) did not respond" in result.summary
+
+
+def test_the_real_report_fits_the_metrics_review_classification():
+    """Every check that fails on main is a no-worsening check, and every
+    metric kind has a review bound, so a pair compared with itself passes."""
+
+    from policyengine.provenance.uk_candidate import classify_check
+
+    report = _real_report()
+    bounds = json.loads(
+        (
+            Path(__file__).parents[1]
+            / "src/policyengine/data/qualification/uk_review_bounds.json"
+        ).read_text()
+    )
+    failing = sorted(
+        row["identity_id"] for row in report["identities"] if row["status"] == "fail"
+    )
+    assert failing == [
+        "counted_once:statutory_maternity_pay",
+        "counted_once:statutory_sick_pay",
+        "overlap_guard:property_transaction_tax_geography",
+        "sign:vat",
+    ]
+    assert {classify_check(check_id) for check_id in failing} == {"regression"}
+    assert {row["kind"] for row in report["metrics"]} <= set(bounds["kinds"])
+    status, summary, evidence = compare_metric_reports(report, report, bounds)
+    assert status == "pass", summary
+    assert sorted(evidence["preexisting_check_failures"]) == failing
+    # The same failures against a pair that passed them are regressions.
+    clean = _real_report()
+    for row in clean["identities"]:
+        if row["status"] == "fail":
+            row["status"] = "pass"
+    assert compare_metric_reports(report, clean, bounds)[0] == "fail"
+
+
 def test_reform_checks_are_hard_in_the_metrics_review():
     from policyengine.provenance.uk_candidate import classify_check
 

From b424ffb4a8c9fb6203919c381d5fc185515dbd26 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 19:56:03 -0400
Subject: [PATCH 13/45] Test scope-based no-worsening on the tool's real
 failing scopes

Swap the real metrics report for the one produced at the pinned tool
commit (bd8bff74c), whose check rows carry failing_scopes. Its 1,470
metric rows are identical to the earlier run's. On it, sign:vat and the
overlap guard fail in all seven years and the two counted-once failures
have no year. A candidate that fails sign:vat in a year the previous pair
did not has worsened and fails; one that fails it in fewer years passes.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 tests/fixtures/uk_metrics/README.md           |  12 +-
 .../uk_metrics/budget_metrics_report.json     | 474 ++++++++++++++++++
 tests/test_uk_candidate_gates.py              |  28 ++
 3 files changed, 507 insertions(+), 7 deletions(-)

diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index dfd8c913..a5976b28 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -12,10 +12,8 @@ pinned commit; never edit them by hand.
   the least it must move it in every year. The reform responsiveness gate
   reads the same file from the vendored tool.
 - `budget_metrics_report.json`: a real `compute_budget_metrics` report from
-  the tool's owner (workstream W3), run on 11 October 2026 on uk-data 1.58.0
-  (`enhanced_frs_2024_25`) with policyengine-uk main, for 2025-26 to 2031-32,
-  with the overlap guard and the ten standard reforms. It holds aggregates
-  only: 1,470 metric rows and 346 checks (327 pass, 15 warn, 4 fail). It was
-  produced at tool commit `c7a6c963991b4873a51042bda640f28eb914e34e`, one
-  commit before the pin; the only change since adds `failing_scopes` to each
-  check row, so this report has no `failing_scopes`.
+  the tool's owner (workstream W3), run on 11 October 2026 at the pinned tool
+  commit on uk-data 1.58.0 (`enhanced_frs_2024_25`) with policyengine-uk main,
+  for 2025-26 to 2031-32, with the overlap guard and the ten standard reforms.
+  It holds aggregates only: 1,470 metric rows and 346 checks (327 pass,
+  15 warn, 4 fail), each check with its `failing_scopes`.
diff --git a/tests/fixtures/uk_metrics/budget_metrics_report.json b/tests/fixtures/uk_metrics/budget_metrics_report.json
index c79f1a06..6b599fb5 100644
--- a/tests/fixtures/uk_metrics/budget_metrics_report.json
+++ b/tests/fixtures/uk_metrics/budget_metrics_report.json
@@ -13250,6 +13250,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13257,6 +13258,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13264,6 +13266,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13271,6 +13274,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13278,6 +13282,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13285,6 +13290,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13292,6 +13298,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13299,6 +13306,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13306,6 +13314,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13313,6 +13322,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13320,6 +13330,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13327,6 +13338,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13334,6 +13346,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13341,6 +13354,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13348,6 +13362,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13355,6 +13370,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13362,6 +13378,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13369,6 +13386,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13376,6 +13394,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13383,6 +13402,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13390,6 +13410,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13397,6 +13418,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13404,6 +13426,15 @@
    "year": null,
    "status": "fail",
    "severity": "fail",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: 76 units below zero, a weighted \u00a3-69,996,281 in total; 2026-27: 76 units below zero, a weighted \u00a3-71,878,301 in total; 2027-28: 76 units below zero, a weighted \u00a3-73,587,136 in total; 2028-29: 76 units below zero, a weighted \u00a3-75,359,106 in total; 2029-30: 76 units below zero, a weighted \u00a3-77,204,504 in total; 2030-31: 76 units below zero, a weighted \u00a3-79,102,963 in total; 2031-32: 76 units below zero, a weighted \u00a3-81,032,183 in total"
   },
   {
@@ -13411,6 +13442,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13418,6 +13450,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13425,6 +13458,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13432,6 +13466,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13439,6 +13474,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13446,6 +13482,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13453,6 +13490,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13460,6 +13498,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13467,6 +13506,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13474,6 +13514,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -13481,6 +13530,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13488,6 +13538,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13495,6 +13546,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -13502,6 +13562,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13509,6 +13570,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13516,6 +13578,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -13523,6 +13594,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13530,6 +13602,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13537,6 +13610,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13544,6 +13618,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13551,6 +13626,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13558,6 +13634,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13565,6 +13642,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13572,6 +13650,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13579,6 +13658,11 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit"
   },
   {
@@ -13586,6 +13670,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13593,6 +13678,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13600,6 +13686,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13607,6 +13694,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13614,6 +13702,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13621,6 +13710,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13628,6 +13718,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13635,6 +13726,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13642,6 +13734,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13649,6 +13742,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13656,6 +13750,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13663,6 +13758,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13670,6 +13766,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13677,6 +13774,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13684,6 +13782,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13691,6 +13790,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13698,6 +13798,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13705,6 +13806,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13712,6 +13814,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13719,6 +13822,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13726,6 +13830,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13733,6 +13838,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13740,6 +13846,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13747,6 +13854,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13754,6 +13862,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13761,6 +13870,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13768,6 +13878,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13775,6 +13886,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13782,6 +13894,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13789,6 +13902,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13796,6 +13910,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13803,6 +13918,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13810,6 +13926,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13817,6 +13934,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13824,6 +13942,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13831,6 +13950,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13838,6 +13958,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13845,6 +13966,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13852,6 +13974,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13859,6 +13982,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13866,6 +13990,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13873,6 +13998,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13880,6 +14006,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13887,6 +14014,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13894,6 +14022,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13901,6 +14030,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13908,6 +14038,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13915,6 +14046,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13922,6 +14054,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13929,6 +14062,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13936,6 +14070,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13943,6 +14078,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13950,6 +14086,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13957,6 +14094,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13964,6 +14102,14 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -13971,6 +14117,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13978,6 +14125,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13985,6 +14133,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13992,6 +14141,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -13999,6 +14149,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14006,6 +14157,14 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14013,6 +14172,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14020,6 +14180,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14027,6 +14188,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14034,6 +14204,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14041,6 +14212,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14048,6 +14220,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14055,6 +14236,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14062,6 +14244,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14069,6 +14252,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14076,6 +14268,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14083,6 +14276,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14090,6 +14284,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14097,6 +14292,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14104,6 +14300,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14111,6 +14308,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14118,6 +14316,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14125,6 +14324,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14132,6 +14332,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14139,6 +14340,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14146,6 +14348,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14153,6 +14356,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14160,6 +14364,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14167,6 +14372,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14174,6 +14380,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14181,6 +14388,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14188,6 +14396,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14195,6 +14404,9 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025"
+   ],
    "detail": "2025-26: zero for every unit"
   },
   {
@@ -14202,6 +14414,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14209,6 +14422,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14216,6 +14430,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14223,6 +14438,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14230,6 +14446,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14237,6 +14454,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14244,6 +14462,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14251,6 +14470,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14258,6 +14478,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14265,6 +14486,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14272,6 +14494,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14279,6 +14502,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14286,6 +14510,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14293,6 +14518,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14300,6 +14526,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14307,6 +14534,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14314,6 +14542,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14321,6 +14550,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14328,6 +14558,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14335,6 +14566,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14342,6 +14574,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14349,6 +14582,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14356,6 +14590,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14363,6 +14606,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14370,6 +14614,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14377,6 +14622,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14384,6 +14630,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14391,6 +14638,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14398,6 +14646,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14405,6 +14654,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14412,6 +14662,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14419,6 +14670,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14426,6 +14678,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14433,6 +14686,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14440,6 +14694,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14447,6 +14702,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14454,6 +14710,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14461,6 +14718,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14468,6 +14726,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14475,6 +14734,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14482,6 +14742,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14489,6 +14750,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14496,6 +14758,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14503,6 +14766,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14510,6 +14774,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14517,6 +14782,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14524,6 +14790,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14531,6 +14798,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14538,6 +14806,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14545,6 +14814,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14552,6 +14830,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14559,6 +14838,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14566,6 +14846,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14573,6 +14862,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14580,6 +14870,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14587,6 +14878,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14594,6 +14886,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14601,6 +14894,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14608,6 +14902,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14615,6 +14910,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14622,6 +14918,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14629,6 +14926,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14636,6 +14942,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14643,6 +14950,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14650,6 +14958,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14657,6 +14966,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14664,6 +14974,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14671,6 +14982,15 @@
    "year": null,
    "status": "warn",
    "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
   },
   {
@@ -14678,6 +14998,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14685,6 +15006,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14692,6 +15014,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14699,6 +15022,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14706,6 +15030,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14713,6 +15038,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14720,6 +15046,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14727,6 +15054,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14734,6 +15062,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14741,6 +15070,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14748,6 +15078,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14755,6 +15086,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14762,6 +15094,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14769,6 +15102,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14776,6 +15110,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14783,6 +15118,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14790,6 +15126,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14797,6 +15134,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14804,6 +15142,15 @@
    "year": null,
    "status": "fail",
    "severity": "fail",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
    "detail": "2025-26: 86 households have more than one, a weighted 39,273; 2026-27: 86 households have more than one, a weighted 39,422; 2027-28: 88 households have more than one, a weighted 39,718; 2028-29: 92 households have more than one, a weighted 40,335; 2029-30: 94 households have more than one, a weighted 40,724; 2030-31: 96 households have more than one, a weighted 41,410; 2031-32: 104 households have more than one, a weighted 42,213"
   },
   {
@@ -14811,6 +15158,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14818,6 +15166,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14825,6 +15174,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14832,6 +15182,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14839,6 +15190,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14846,6 +15198,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14853,6 +15206,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14860,6 +15214,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14867,6 +15222,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14874,6 +15230,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14881,6 +15238,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14888,6 +15246,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14895,6 +15254,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14902,6 +15262,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14909,6 +15270,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14916,6 +15278,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14923,6 +15286,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14930,6 +15294,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14937,6 +15302,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14944,6 +15310,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14951,6 +15318,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14958,6 +15326,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14965,6 +15334,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14972,6 +15342,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14979,6 +15350,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14986,6 +15358,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -14993,6 +15366,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15000,6 +15374,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15007,6 +15382,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15014,6 +15390,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15021,6 +15398,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15028,6 +15406,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15035,6 +15414,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15042,6 +15422,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15049,6 +15430,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15056,6 +15438,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15063,6 +15446,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15070,6 +15454,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15077,6 +15462,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15084,6 +15470,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15091,6 +15478,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15098,6 +15486,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15105,6 +15494,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15112,6 +15502,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15119,6 +15510,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15126,6 +15518,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15133,6 +15526,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15140,6 +15534,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15147,6 +15542,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15154,6 +15550,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15161,6 +15558,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15168,6 +15566,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15175,6 +15574,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15182,6 +15582,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15189,6 +15590,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15196,6 +15598,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15203,6 +15606,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15210,6 +15614,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15217,6 +15622,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15224,6 +15630,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15231,6 +15638,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15238,6 +15646,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15245,6 +15654,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15252,6 +15662,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15259,6 +15670,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15266,6 +15678,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15273,6 +15686,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15280,6 +15694,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15287,6 +15702,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15294,6 +15710,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15301,6 +15718,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15308,6 +15726,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15315,6 +15734,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15322,6 +15742,9 @@
    "year": null,
    "status": "fail",
    "severity": "fail",
+   "failing_scopes": [
+    ""
+   ],
    "detail": "gov_spending: universal_credit rises by 0.0068 per unit of statutory_maternity_pay; household_benefits: universal_credit rises by 0.0068 per unit of statutory_maternity_pay"
   },
   {
@@ -15329,6 +15752,9 @@
    "year": null,
    "status": "fail",
    "severity": "fail",
+   "failing_scopes": [
+    ""
+   ],
    "detail": "gov_spending: universal_credit rises by 0.0099 per unit of statutory_sick_pay; household_benefits: universal_credit rises by 0.0099 per unit of statutory_sick_pay"
   },
   {
@@ -15336,6 +15762,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15343,6 +15770,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15350,6 +15778,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15357,6 +15786,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15364,6 +15794,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15371,6 +15802,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15378,6 +15810,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15385,6 +15818,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15392,6 +15826,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15399,6 +15834,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15406,6 +15842,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15413,6 +15850,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15420,6 +15858,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15427,6 +15866,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15434,6 +15874,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15441,6 +15882,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15448,6 +15890,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15455,6 +15898,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15462,6 +15906,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15469,6 +15914,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15476,6 +15922,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15483,6 +15930,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15490,6 +15938,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15497,6 +15946,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15504,6 +15954,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15511,6 +15962,7 @@
    "year": null,
    "status": "pass",
    "severity": "warn",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15518,6 +15970,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15525,6 +15978,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15532,6 +15986,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15539,6 +15994,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15546,6 +16002,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15553,6 +16010,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15560,6 +16018,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15567,6 +16026,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15574,6 +16034,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15581,6 +16042,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15588,6 +16050,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15595,6 +16058,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15602,6 +16066,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15609,6 +16074,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15616,6 +16082,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15623,6 +16090,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15630,6 +16098,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15637,6 +16106,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15644,6 +16114,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15651,6 +16122,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15658,6 +16130,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   },
   {
@@ -15665,6 +16138,7 @@
    "year": null,
    "status": "pass",
    "severity": "fail",
+   "failing_scopes": [],
    "detail": ""
   }
  ]
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index f67926bd..3c68d46b 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1557,6 +1557,34 @@ def test_the_real_report_fits_the_metrics_review_classification():
     assert compare_metric_reports(report, clean, bounds)[0] == "fail"
 
 
+def test_a_real_failure_that_spread_to_a_new_year_has_worsened():
+    """Scope-based no-worsening on the tool's real failing_scopes."""
+
+    bounds = json.loads(
+        (
+            Path(__file__).parents[1]
+            / "src/policyengine/data/qualification/uk_review_bounds.json"
+        ).read_text()
+    )
+    report = _real_report()
+    scopes = {
+        row["identity_id"]: row["failing_scopes"]
+        for row in report["identities"]
+        if row["status"] == "fail"
+    }
+    assert scopes["sign:vat"] == [str(year) for year in RESPONSE_YEARS]
+    assert scopes["counted_once:statutory_sick_pay"] == [""]
+    # The previous pair failed sign:vat in every year but the last.
+    earlier = _real_report()
+    for row in earlier["identities"]:
+        if row["identity_id"] == "sign:vat":
+            row["failing_scopes"] = row["failing_scopes"][:-1]
+    status, summary, _ = compare_metric_reports(report, earlier, bounds)
+    assert status == "fail" and "sign:vat (fails in more scopes)" in summary
+    # A candidate that fails it in fewer years than before has not worsened.
+    assert compare_metric_reports(earlier, report, bounds)[0] == "pass"
+
+
 def test_reform_checks_are_hard_in_the_metrics_review():
     from policyengine.provenance.uk_candidate import classify_check
 

From ee78f5e789447f4d4b79545165330b979ebcf919 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 20:12:27 -0400
Subject: [PATCH 14/45] Close gate holes found by review: partial reports and
 self-contradicting receipts

An independent review of #574 was cut off by a transport failure, but its
reproductions showed ten ways a gate passed without evidence. All ten
are fixed here and tested.

Reform contract:
- A full run must cover what the runner's own module declares (ROUTES,
  each case in CASES on its routes, PROPERTIES). A recounted partial
  report, a dropped route, case or property, or a runner that declares
  no coverage is an error.
- A sampled property that passed must have run the examples requested.

Metrics review:
- A report whose status is not ok, or with no metrics or no checks, fails
  (two empty reports used to compare as a pass).
- A check with a status outside pass, warn, fail and skipped fails.
- A hard check the previous pair ran that the candidate lacks fails;
  other vanished checks need review.

Replay:
- Flags count wherever the receipt states them, never from the summary
  counters alone, and a receipt that contradicts itself fails: flagged
  rows of a kind exceeding its count, failures under a complete
  integrity, supported years with no artifacts, nothing replayed.
- The comparison base must be the one the request asked for.
- Inert measure-years with no inertness flag need review.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/qualification.py |  89 ++++++++--
 src/policyengine/provenance/uk_candidate.py  | 136 ++++++++++++++-
 tests/test_qualification_contracts.py        |  93 +++++++++-
 tests/test_uk_candidate_gates.py             | 170 ++++++++++++++++++-
 4 files changed, 462 insertions(+), 26 deletions(-)

diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index bddb2b86..8ed36430 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -743,6 +743,14 @@ def evaluate_replay_receipt(
     Rejected or failed replays, incomplete runs and blocking flags fail the
     gate; numerical and support flags need review. Unsupported years are
     reported, never failed on their own.
+
+    The receipt is read as a whole, not by its summary counters: a flag
+    counts when either ``flag_counts`` or a flagged row carries it, and a
+    receipt that contradicts itself fails (failures listed under a complete
+    integrity, more flagged rows of a kind than its count, supported years
+    with no artifacts, nothing replayed at all) or contradicts the request
+    (a comparison base other than the ``compare_to`` asked for). Inert
+    measure-years with no inertness flag need review.
     """
 
     request_id = request.request_id
@@ -889,31 +897,92 @@ def evaluate_replay_receipt(
             ),
             details={**details, "incomplete_events": incomplete_events},
         )
+    # A receipt whose parts disagree is not evidence of anything.
+    contradictions: list[str] = []
+    if receipt.integrity.failures:
+        codes = sorted({failure.code for failure in receipt.integrity.failures})
+        contradictions.append(
+            f"integrity is complete but lists failures ({', '.join(codes)})"
+        )
+    replayed = 0
+    for name, event in sorted(corpus.events.items()):
+        replayed += event.artifacts
+        if event.supported_years and event.artifacts == 0:
+            contradictions.append(f"{name} has supported years but no artifacts")
+        if not event.supported_years and not event.unsupported_years:
+            contradictions.append(f"{name} names no years at all")
+    if replayed == 0:
+        contradictions.append("no measure-year was replayed")
     counts = receipt.diff.flag_counts.document() if receipt.diff is not None else {}
+    rows = receipt.diff.flagged_rows if receipt.diff is not None else []
+    row_counts: dict[str, int] = {}
+    for row in rows:
+        for kind in row.flags:
+            row_counts[kind] = row_counts.get(kind, 0) + 1
+    for kind, seen in sorted(row_counts.items()):
+        if counts.get(kind, 0) < seen:
+            contradictions.append(
+                f"{seen} flagged row(s) carry {kind} but flag_counts says "
+                f"{counts.get(kind, 0)}"
+            )
     details["flag_counts"] = counts
+    details["flagged_row_counts"] = row_counts
     if receipt.diff is not None:
         details["base_variant_id"] = receipt.diff.base_variant_id
         details["diff_sha256"] = receipt.diff.diff_sha256
-    blocking = {
-        kind: n for kind, n in counts.items() if kind in BLOCKING_REPLAY_FLAGS and n
-    }
-    review = {
-        kind: n for kind, n in counts.items() if kind in REVIEW_REPLAY_FLAGS and n
-    }
+    if request.compare_to != "latest_certified":
+        base = receipt.diff.base_variant_id if receipt.diff is not None else None
+        if base != request.compare_to:
+            contradictions.append(
+                f"the request asked for a comparison with {request.compare_to}, "
+                f"but the receipt compares with {base}"
+            )
+    if contradictions:
+        return GateResult(
+            gate_id="replay",
+            status="fail",
+            summary="Replay receipt contradicts itself or the request: "
+            + "; ".join(contradictions),
+            details={**details, "contradictions": contradictions},
+        )
+    # Flags come from every place the receipt can state them, never from the
+    # summary counters alone.
+    present = {kind for kind, n in counts.items() if n} | set(row_counts)
+    blocking = sorted(present & BLOCKING_REPLAY_FLAGS)
+    review = sorted(present & REVIEW_REPLAY_FLAGS)
+
+    def tally(kinds: Sequence[str]) -> str:
+        return ", ".join(
+            f"{kind} {max(counts.get(kind, 0), row_counts.get(kind, 0))}"
+            for kind in kinds
+        )
+
     if blocking:
         return GateResult(
             gate_id="replay",
             status="fail",
-            summary="Blocking replay flags: "
-            + ", ".join(f"{kind} {n}" for kind, n in sorted(blocking.items())),
+            summary="Blocking replay flags: " + tally(blocking),
             details=details,
         )
     if review:
         return GateResult(
             gate_id="replay",
             status="needs_review",
-            summary="Replay moves need review: "
-            + ", ".join(f"{kind} {n}" for kind, n in sorted(review.items())),
+            summary="Replay moves need review: " + tally(review),
+            details=details,
+        )
+    if inert:
+        # A measure that does nothing in a supported year, with no inertness
+        # flag against the base: unchanged from the base, but still a measure
+        # the model does not respond to. A person decides whether it is known.
+        return GateResult(
+            gate_id="replay",
+            status="needs_review",
+            summary=(
+                f"{len(inert)} replayed measure-year(s) are inert, with no "
+                "inertness flag against the base: "
+                + ", ".join(f"{m} {y}" for _, m, y in inert[:6])
+            ),
             details=details,
         )
     if receipt.diff is None:
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 13903549..a8bdc845 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -610,13 +610,42 @@ def budget_inputs(
 
 def _load_entrypoint(
     entrypoint: str, importer: Callable[[str], Any]
-) -> Callable[..., Any]:
+) -> tuple[Callable[..., Any], Any]:
+    """The entrypoint's callable and the module that defines it."""
+
     module_name, _, attribute = entrypoint.partition(":")
     if not attribute:
         module_name, _, attribute = entrypoint.rpartition(".")
     module = importer(module_name)
     function: Callable[..., Any] = getattr(module, attribute)
-    return function
+    return function, module
+
+
+def _contract_coverage(module: Any) -> Optional[dict[str, list[Any]]]:
+    """What a full contract run covers, as the runner's own module declares it.
+
+    ``ROUTES`` (route ids), ``CASES`` (objects with an ``id`` and optional
+    ``routes`` limiting where the case runs) and ``PROPERTIES`` (keyed by
+    property id). ``None`` when the module does not declare them, so coverage
+    cannot be checked.
+    """
+
+    try:
+        routes = [str(route) for route in module.ROUTES]
+        pairs = [
+            (str(case.id), str(route))
+            for case in module.CASES
+            for route in (
+                case.routes if getattr(case, "routes", None) is not None else routes
+            )
+        ]
+        return {
+            "routes": routes,
+            "pairs": pairs,
+            "properties": [str(name) for name in module.PROPERTIES],
+        }
+    except AttributeError:
+        return None
 
 
 #: Report sections: the key that names each row, and what a row is called.
@@ -643,6 +672,10 @@ def reform_contract(
     ``fail`` when any case, sampled property or population check fails or
     errors. ``error`` when the report cannot be trusted as a full run of this
     candidate:
+    - it does not cover every route, every case on each of its routes and
+      every sampled property the runner's module declares (``ROUTES``,
+      ``CASES``, ``PROPERTIES``), or a property passed on fewer examples than
+      requested;
     - a pending row lacks its ``decision_id``, or an unsupported case or
       population check lacks its ``reason``;
     - a sampled property did not run;
@@ -660,7 +693,7 @@ def reform_contract(
             {},
         )
     try:
-        runner = _load_entrypoint(entrypoint, importer)
+        runner, runner_module = _load_entrypoint(entrypoint, importer)
     except (ImportError, AttributeError) as exc:
         return _result(
             "reform_contract",
@@ -714,6 +747,55 @@ def reform_contract(
                 malformed.append(f"{label} has unknown status {status!r}")
     if not report.get("cases"):
         malformed.append("the report has no cases")
+    # A full run covers what the runner itself declares: every route, every
+    # case on each route it runs on, and every sampled property with the
+    # examples asked for. A report that drops any of it does not qualify.
+    coverage = _contract_coverage(runner_module)
+    if coverage is None:
+        malformed.append(
+            "the runner declares no ROUTES, CASES and PROPERTIES, so the "
+            "report's coverage cannot be checked"
+        )
+    else:
+        reported_routes = [str(route) for route in report.get("routes") or []]
+        if sorted(reported_routes) != sorted(coverage["routes"]):
+            malformed.append(
+                f"the report covers routes {sorted(reported_routes)}, not "
+                f"{sorted(coverage['routes'])}"
+            )
+        covered = {
+            (str(row.get("case_id")), str(row.get("route")))
+            for row in report.get("cases") or []
+        }
+        absent = [
+            f"{case}@{route}"
+            for case, route in coverage["pairs"]
+            if (case, route) not in covered
+        ]
+        if absent:
+            malformed.append(
+                f"{len(absent)} case-route pair(s) have no row: "
+                + ", ".join(absent[:4])
+            )
+        properties = {
+            str(row.get("property_id")): row for row in report.get("properties") or []
+        }
+        for name in coverage["properties"]:
+            row = properties.get(name)
+            if row is None:
+                malformed.append(f"property {name} has no row")
+            elif row.get("status") == "pass":
+                examples = row.get("examples_run")
+                if (
+                    isinstance(examples, bool)
+                    or not isinstance(examples, int)
+                    or examples < max_examples
+                    or examples < 1
+                ):
+                    malformed.append(
+                        f"property {name} passed on {examples} example(s), "
+                        f"not the {max_examples} requested"
+                    )
     if dataset_path is not None and not report.get("population"):
         malformed.append("a dataset was given but no population checks ran")
     for field, requested in (("seed", seed), ("max_examples", max_examples)):
@@ -812,6 +894,10 @@ def _bound(bounds: Mapping[str, Any], kind: Optional[str]) -> tuple[float, float
 )
 
 
+#: The statuses the metrics tool gives a check. Anything else fails.
+CHECK_STATUSES = frozenset({"pass", "warn", "fail", "skipped"})
+
+
 def classify_check(identity_id: str) -> str:
     """``hard``, ``regression`` or ``hard`` for an unknown check (no skips)."""
 
@@ -848,12 +934,25 @@ def compare_metric_reports(
     them); ``warn`` is recorded, and a check that newly warns, or is skipped
     where the previous pair passed it, needs review. ``skipped`` is neither a
     pass nor a failure.
+
+    A report with a status other than ``ok``, no metrics or no checks fails,
+    as does any check with a status outside ``CHECK_STATUSES``. A hard check
+    the previous pair ran that is missing from the candidate fails (the two
+    reports share one tool and one set of definitions); other missing checks
+    need review.
     """
 
     problems: list[str] = []
     review: list[str] = []
-    if candidate.get("status") not in (None, "ok"):
-        problems.append(f"the candidate report status is {candidate.get('status')!r}")
+    # An empty or unfinished report measures nothing; it must never read as
+    # "no moves beyond the bounds".
+    for name, report in (("candidate", candidate), ("previous", previous)):
+        if report.get("status") != "ok":
+            problems.append(f"the {name} report status is {report.get('status')!r}")
+        if not report.get("metrics"):
+            problems.append(f"the {name} report has no metrics")
+        if not report.get("identities"):
+            problems.append(f"the {name} report has no checks")
     previous_rows = {
         str(row.get("identity_id")): row for row in previous.get("identities", [])
     }
@@ -863,12 +962,17 @@ def compare_metric_reports(
     new_warnings: list[str] = []
     warnings_: list[str] = []
     newly_skipped: list[str] = []
+    unknown_statuses: list[str] = []
+    candidate_checks = set()
     for row in candidate.get("identities", []):
         check_id = str(row.get("identity_id"))
+        candidate_checks.add(check_id)
         status = row.get("status")
         earlier = previous_rows.get(check_id) or {}
         before = earlier.get("status")
-        if status == "fail":
+        if status not in CHECK_STATUSES:
+            unknown_statuses.append(f"{check_id} ({status!r})")
+        elif status == "fail":
             if classify_check(check_id) == "hard":
                 hard_failures.append(check_id)
             elif before != "fail":
@@ -883,6 +987,24 @@ def compare_metric_reports(
                 new_warnings.append(check_id)
         elif status == "skipped" and before == "pass":
             newly_skipped.append(check_id)
+    if unknown_statuses:
+        # A status this gate does not know is not a pass.
+        problems.append(
+            f"checks with an unknown status: {', '.join(unknown_statuses[:8])}"
+        )
+    # A check the previous pair ran and the candidate did not: the tool and
+    # its definitions are the same (metrics_version), so coverage was lost.
+    lost_checks = sorted(set(previous_rows) - candidate_checks)
+    lost_hard = [
+        check_id
+        for check_id in lost_checks
+        if classify_check(check_id) == "hard"
+        and candidate.get("partition_version") == previous.get("partition_version")
+    ]
+    if lost_hard:
+        problems.append(f"checks disappeared: {', '.join(lost_hard[:8])}")
+    elif lost_checks:
+        review.append(f"checks disappeared: {', '.join(lost_checks[:8])}")
     if hard_failures:
         problems.append(f"checks failed: {', '.join(hard_failures[:8])}")
     if regressions:
@@ -957,6 +1079,8 @@ def compare_metric_reports(
         "warn_identities": warnings_,
         "new_warnings": new_warnings,
         "newly_skipped_checks": newly_skipped,
+        "unknown_status_checks": unknown_statuses,
+        "lost_checks": lost_checks,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
diff --git a/tests/test_qualification_contracts.py b/tests/test_qualification_contracts.py
index bc54bdf2..92975466 100644
--- a/tests/test_qualification_contracts.py
+++ b/tests/test_qualification_contracts.py
@@ -441,12 +441,20 @@ def _gate(receipt_doc, request=None, status=None):
     )
 
 
-def _with_counts(**counts):
+def _with_counts(sealed=True, **counts):
+    """The golden receipt with these flag counts and one flagged row per flag."""
+
     doc = copy.deepcopy(golden("replay_receipt_golden"))
     base = {key: 0 for key in doc["diff"]["flag_counts"]}
     base.update(counts)
     doc["diff"]["flag_counts"] = base
-    return _sealed(doc)
+    template = doc["diff"]["flagged_rows"][0]
+    doc["diff"]["flagged_rows"] = [
+        {**template, "flags": [kind], "year": 2024 + index}
+        for kind, count in counts.items()
+        for index in range(count)
+    ]
+    return _sealed(doc) if sealed else doc
 
 
 def test_golden_receipt_fails_on_its_structural_flag():
@@ -471,6 +479,87 @@ def test_flag_policy(counts, status):
     assert _gate(_with_counts(**counts)).status == status
 
 
+def _clean_receipt():
+    return _with_counts(sealed=False)
+
+
+def _edit(receipt, edit):
+    edit(receipt)
+    return _sealed(receipt)
+
+
+EVENT = "spring_budget_2023"
+
+CONTRADICTIONS = {
+    "a structural row with zero counts": lambda r: r["diff"].update(
+        flagged_rows=[{**golden("replay_receipt_golden")["diff"]["flagged_rows"][1]}]
+    ),
+    "a failure under complete integrity": lambda r: r["integrity"].update(
+        failures=[{"code": "construction", "detail": "measure failed"}]
+    ),
+    "supported years with no artifacts": lambda r: r["corpus"]["events"][EVENT].update(
+        artifacts=0
+    ),
+    "nothing replayed": lambda r: r["corpus"]["events"][EVENT].update(
+        artifacts=0, supported_years=[]
+    ),
+    "an event with no years": lambda r: r["corpus"]["events"][EVENT].update(
+        supported_years=[], unsupported_years=[]
+    ),
+}
+
+
+@pytest.mark.parametrize("name", sorted(CONTRADICTIONS))
+def test_a_receipt_that_contradicts_itself_fails(name):
+    """Interrupted review of #574: each of these was schema-valid, correctly
+    digested, and passed the gate because the summary counters were zero."""
+
+    receipt = _edit(_clean_receipt(), CONTRADICTIONS[name])
+    _validator("replay_receipt.v1.json").validate(receipt)
+    gate = _gate(receipt)
+    assert gate.status == "fail", (name, gate.summary)
+    assert "contradicts itself or the request" in gate.summary
+
+
+def test_blocking_flags_count_wherever_the_receipt_states_them():
+    """A row's flag blocks even when its counter is understated."""
+
+    receipt = _with_counts(sealed=False, numerical=1)
+    receipt["diff"]["flagged_rows"].append(
+        {**receipt["diff"]["flagged_rows"][0], "flags": ["mapping"], "year": 2030}
+    )
+    receipt["diff"]["flag_counts"]["mapping"] = 1
+    assert _gate(_sealed(receipt)).status == "fail"
+    assert "mapping" in _gate(_sealed(receipt)).summary
+
+
+def test_an_inert_measure_year_without_a_flag_needs_review():
+    receipt = _edit(
+        _clean_receipt(),
+        lambda r: r["corpus"]["events"][EVENT].update(
+            inert_measure_years=[{"measure_key": "uc_childcare", "year": 2026}]
+        ),
+    )
+    gate = _gate(receipt)
+    assert gate.status == "needs_review" and "inert" in gate.summary
+
+
+def test_the_comparison_base_must_be_the_one_requested():
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    base_variant = _clean_receipt()["diff"]["base_variant_id"]
+    raw["compare_to"] = base_variant
+    explicit = ReplayQualificationRequest.model_validate(raw)
+    receipt = _clean_receipt()
+    receipt["request_id"] = explicit.request_id
+    assert _gate(_sealed(receipt), request=explicit).status == "pass"
+    raw["compare_to"] = "pe6.2.6_uk2.125.1_policyengine-uk-data-1.58.0"
+    other = ReplayQualificationRequest.model_validate(raw)
+    receipt = _clean_receipt()
+    receipt["request_id"] = other.request_id
+    gate = _gate(_sealed(receipt), request=other)
+    assert gate.status == "fail" and "asked for a comparison" in gate.summary
+
+
 def test_incomplete_or_failed_integrity_fails():
     doc = copy.deepcopy(golden("replay_receipt_golden"))
     doc["diff"]["flag_counts"] = {key: 0 for key in doc["diff"]["flag_counts"]}
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 3c68d46b..5ca25c7e 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -542,7 +542,34 @@ def test_critical_inputs_file_lists_real_model_inputs():
 # --- Reform contract -----------------------------------------------------------------
 
 
-def _importer(report=None, raises=None, missing=False):
+def _declared_coverage(source):
+    """ROUTES, CASES and PROPERTIES as a runner module declares them, read
+    from a report of a full run (each case limited to the routes it ran on)."""
+
+    source = source or {}
+    by_case = {}
+    for row in source.get("cases") or []:
+        by_case.setdefault(row.get("case_id"), []).append(row.get("route"))
+    return {
+        "ROUTES": tuple(source.get("routes") or ()),
+        "CASES": tuple(
+            SimpleNamespace(id=case, routes=tuple(dict.fromkeys(routes)))
+            for case, routes in by_case.items()
+        ),
+        "PROPERTIES": {
+            row.get("property_id"): "" for row in source.get("properties") or []
+        },
+    }
+
+
+def _importer(report=None, raises=None, missing=False, coverage=None, declare=True):
+    """A runner module returning ``report``.
+
+    It declares the coverage of ``coverage`` (a report of a full run), by
+    default ``report`` itself, so a test of row statuses is not also a test
+    of coverage.
+    """
+
     def runner(**kwargs):
         if raises:
             raise raises
@@ -551,7 +578,12 @@ def runner(**kwargs):
     def importer(name):
         if missing:
             raise ModuleNotFoundError(name)
-        return SimpleNamespace(run_budget_reform_contract=runner)
+        declared = (
+            _declared_coverage(coverage if coverage is not None else report)
+            if declare
+            else {}
+        )
+        return SimpleNamespace(run_budget_reform_contract=runner, **declared)
 
     return importer
 
@@ -689,13 +721,20 @@ def _passing_report() -> dict:
     return _fixture("full_allpass_uk_2.126.8.json")
 
 
-def _run_contract(report, *, versions=None, dataset_sha=CERTIFIED_SHA, **kwargs):
+def _run_contract(
+    report, *, versions=None, dataset_sha=CERTIFIED_SHA, coverage=None, **kwargs
+):
+    """Gate ``report`` against the coverage of W1's real full run (or ``coverage``)."""
+
     kwargs.setdefault("seed", 0)
     kwargs.setdefault("max_examples", 20)
     kwargs.setdefault("dataset_path", Path("enhanced_frs_2024_25.h5"))
     return reform_contract(
         entrypoint=ENTRY,
-        importer=_importer(report=report),
+        importer=_importer(
+            report=report,
+            coverage=coverage if coverage is not None else _passing_report(),
+        ),
         expected_versions=versions
         or {"policyengine-uk": "2.126.8", "policyengine-core": "3.33.0"},
         expected_dataset_sha256=dataset_sha,
@@ -713,6 +752,7 @@ def test_w1_report_on_the_pinned_model_fails_on_its_defects():
         dataset_sha=None,
         dataset_path=None,
         max_examples=report["max_examples"],
+        coverage=report,
     )
     assert result.status == "fail"
     assert result.summary.startswith("101 contract row(s) failed")
@@ -722,9 +762,8 @@ def test_w1_report_on_the_pinned_model_fails_on_its_defects():
 def test_w1_population_run_alone_is_incomplete():
     """W1's real population-only run has no cases and no sampled properties."""
 
-    result = _run_contract(
-        _fixture("population_pass_max_examples_0.json"), max_examples=0
-    )
+    population_only = _fixture("population_pass_max_examples_0.json")
+    result = _run_contract(population_only, max_examples=0, coverage=population_only)
     assert result.status == "error"
     problems = result.details["problems"]
     assert "the report has no cases" in problems
@@ -741,6 +780,68 @@ def test_w1_full_run_passes():
     assert result.details["problems"] == []
 
 
+def _drop(report, **sections):
+    """``report`` with rows removed, its summary and holds recounted."""
+
+    return _recount({**report, **sections})
+
+
+COVERAGE_GAPS = {
+    "one case on one route": lambda r: (
+        _drop(r, cases=r["cases"][:1], population=r["population"][:1], properties=[])
+        | {"routes": r["routes"][:1]}
+    ),
+    "a route": lambda r: _drop(
+        r, cases=[row for row in r["cases"] if row["route"] != "wrapper.policy"]
+    ),
+    "a route from the route list": lambda r: {**r, "routes": r["routes"][:-1]},
+    "a case on one route": lambda r: _drop(
+        r,
+        cases=[
+            row
+            for row in r["cases"]
+            if (row["case_id"], row["route"])
+            != ("extended_freeze", "wrapper.household")
+        ],
+    ),
+    "a sampled property": lambda r: _drop(r, properties=r["properties"][:1]),
+    "every sampled property": lambda r: _drop(r, properties=[]),
+    "the sampled examples": lambda r: {
+        **r,
+        "properties": [{**row, "examples_run": 0} for row in r["properties"]],
+    },
+    "most sampled examples": lambda r: {
+        **r,
+        "properties": [{**row, "examples_run": 19} for row in r["properties"]],
+    },
+}
+
+
+@pytest.mark.parametrize("name", sorted(COVERAGE_GAPS))
+def test_a_report_that_drops_coverage_does_not_qualify(name):
+    """Interrupted review of #574: a recounted partial report passed, as did
+    properties that passed on zero examples."""
+
+    report = COVERAGE_GAPS[name](copy.deepcopy(_passing_report()))
+    result = _run_contract(report)
+    assert result.status == "error", (name, result.summary)
+
+
+def test_a_runner_that_declares_no_coverage_cannot_qualify():
+    report = _passing_report()
+    result = reform_contract(
+        entrypoint=ENTRY,
+        dataset_path=Path("enhanced_frs_2024_25.h5"),
+        seed=0,
+        max_examples=20,
+        expected_versions={"policyengine-uk": "2.126.8", "policyengine-core": "3.33.0"},
+        expected_dataset_sha256=CERTIFIED_SHA,
+        importer=_importer(report=report, declare=False),
+    )[0]
+    assert result.status == "error"
+    assert "declares no ROUTES, CASES and PROPERTIES" in result.summary
+
+
 REPORT_TAMPERING = {
     "other model": lambda r: r["versions"].update({"policyengine-uk": "2.125.1"}),
     "other core": lambda r: r["versions"].update({"policyengine-core": "3.30.0"}),
@@ -807,7 +908,11 @@ def _report(values, **extra):
             {"metric_id": mid, "year": year, "value": value, "kind": kind}
             for (mid, year, kind), value in values.items()
         ],
-        "identities": extra.pop("identities", []),
+        # Every real report carries checks; one always passes here.
+        "identities": [
+            {"identity_id": "weights:household", "status": "pass"},
+            *extra.pop("identities", []),
+        ],
         **extra,
     }
 
@@ -848,6 +953,55 @@ def test_metric_comparison_rules():
     assert status == "pass" and evidence["warn_identities"] == ["inert:alcohol_duty"]
 
 
+def test_reports_that_measure_nothing_fail():
+    """Interrupted review of #574: two empty reports compared as a pass."""
+
+    assert compare_metric_reports({}, {}, BOUNDS)[0] == "fail"
+    full = _report(BASE)
+    for broken in (
+        {**full, "metrics": []},
+        {**full, "identities": []},
+        {**full, "status": "error"},
+        {key: value for key, value in full.items() if key != "status"},
+    ):
+        assert compare_metric_reports(broken, full, BOUNDS)[0] == "fail"
+        assert compare_metric_reports(full, broken, BOUNDS)[0] == "fail"
+
+
+@pytest.mark.parametrize("status", ["error", "unsupported", "pending", None, "PASS"])
+def test_a_check_with_an_unknown_status_is_not_a_pass(status):
+    candidate = _report(BASE, identities=[{"identity_id": "closure", "status": status}])
+    previous = _report(BASE, identities=[{"identity_id": "closure", "status": "pass"}])
+    result = compare_metric_reports(candidate, previous, BOUNDS)
+    assert result[0] == "fail" and "unknown status" in result[1]
+
+
+def test_a_check_that_disappears_is_lost_coverage():
+    previous = _report(
+        BASE,
+        identities=[
+            {"identity_id": "closure", "status": "pass"},
+            {"identity_id": "sign:vat", "status": "pass"},
+        ],
+    )
+    # A hard check that vanished under the same partition fails.
+    no_closure = _report(
+        BASE, identities=[{"identity_id": "sign:vat", "status": "pass"}]
+    )
+    result = compare_metric_reports(no_closure, previous, BOUNDS)
+    assert result[0] == "fail" and "checks disappeared: closure" in result[1]
+    # A no-worsening check that vanished needs a look.
+    no_sign = _report(BASE, identities=[{"identity_id": "closure", "status": "pass"}])
+    assert compare_metric_reports(no_sign, previous, BOUNDS)[0] == "needs_review"
+    # When the model's partition changed, vanished per-head checks need review.
+    repartitioned = _report(
+        BASE,
+        partition_version="p2",
+        identities=[{"identity_id": "sign:vat", "status": "pass"}],
+    )
+    assert compare_metric_reports(repartitioned, previous, BOUNDS)[0] == "needs_review"
+
+
 def _checks(**statuses):
     return [
         {"identity_id": key.replace("__", ":"), "status": value}

From abffac1f8d11c734cbfdafc33b86b52c4e95b532 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 20:22:10 -0400
Subject: [PATCH 15/45] Close certification holes found by review

- A core the publisher never claimed is admitted only by the qualified
  pair, so the certificate's basis is then qualified_exact_pair whatever
  the model's own claim. Before, a claimed model with an unclaimed core
  was certified on the model's basis, the certificate named no pair, and
  no ledger evidence was ever required.
- The evidence check now covers the default dataset's reference (the
  repository, path, revision and bytes the runtime resolves) and the
  certified dataset name, and a record with no model wheel hash is
  refused instead of assumed to match.
- At run time an exact-pair certificate holds only for the core it was
  tested with: the installed core is read and compared.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/certification.py  |  30 ++++-
 src/policyengine/provenance/manifest.py       |  26 +++++
 .../provenance/qualification_ledger.py        |  23 ++--
 tests/test_qualified_pair_certification.py    | 103 +++++++++++++++++-
 4 files changed, 167 insertions(+), 15 deletions(-)

diff --git a/src/policyengine/provenance/certification.py b/src/policyengine/provenance/certification.py
index f095cbe5..e31762f9 100644
--- a/src/policyengine/provenance/certification.py
+++ b/src/policyengine/provenance/certification.py
@@ -251,7 +251,9 @@ def validate_release_manifest(
 
     When ``core_version`` is given, the core must also be the build-time
     core, be covered by ``compatible_core_packages``, or be part of the
-    qualified pair.
+    qualified pair. A core admitted only by the qualification makes the
+    basis ``qualified_exact_pair`` whatever the model's own claim, so the
+    certificate names the pair and its ledger evidence is enforced.
     """
     warnings: list[str] = []
     if "national" not in manifest.default_datasets:
@@ -284,8 +286,20 @@ def validate_release_manifest(
         _specifier_matches(model_version, specifier) for specifier in claim_specifiers
     )
 
-    if core_version is not None:
+    core_rests_on_qualification = core_version is not None and (
         _check_core_compatibility(manifest, core_version, qualified_pair_id, warnings)
+    )
+    if core_rests_on_qualification:
+        # The publisher never claimed this core, so the model's own claim
+        # cannot carry the certificate: it is the exact pair that was tested,
+        # and the certificate must name it so its evidence is checked.
+        warnings.append(
+            f"certifying exactly {model_package}=={model_version} with "
+            f"policyengine-core=={core_version} on automated qualification of "
+            f"pair {qualified_pair_id}; the certificate stands only with a "
+            "promotable qualification receipt for that pair in the ledger"
+        )
+        return BASIS_QUALIFIED_PAIR, warnings
 
     if built_with == model_version:
         return BASIS_BUILT_WITH, warnings
@@ -323,8 +337,12 @@ def _check_core_compatibility(
     core_version: str,
     qualified_pair_id: Optional[str],
     warnings: list[str],
-) -> None:
-    """The core must be the build core, publisher-claimed, or qualified."""
+) -> bool:
+    """The core must be the build core, publisher-claimed, or qualified.
+
+    Returns whether the core is admitted only by the qualification, in which
+    case the certificate's basis must be the qualified exact pair.
+    """
 
     build = manifest.build
     built_with_core = (
@@ -340,14 +358,14 @@ def _check_core_compatibility(
     if built_with_core == core_version or any(
         _specifier_matches(core_version, specifier) for specifier in core_claims
     ):
-        return
+        return False
     if qualified_pair_id is not None:
         warnings.append(
             f"policyengine-core {core_version} is outside the publisher's core "
             f"claims {core_claims or '(none declared)'}; covered by qualification "
             f"of pair {qualified_pair_id}"
         )
-        return
+        return True
     raise CertificationError(
         f"policyengine-core {core_version} matches neither the build-time core "
         f"({built_with_core or 'unrecorded'}) nor any publisher core claim "
diff --git a/src/policyengine/provenance/manifest.py b/src/policyengine/provenance/manifest.py
index 82647384..600d0ac5 100644
--- a/src/policyengine/provenance/manifest.py
+++ b/src/policyengine/provenance/manifest.py
@@ -402,10 +402,32 @@ def _specifier_matches(version: str, specifier: str) -> bool:
         return False
 
 
+def _runtime_core_is_certified(
+    certification: DataCertification, runtime_core_version: Optional[str]
+) -> bool:
+    """Whether the running core is the one an exact-pair certificate tested.
+
+    Other bases make no claim about the core at run time. An exact pair was
+    tested with one core, so it holds only for that core.
+    """
+
+    if certification.compatibility_basis != "qualified_exact_pair":
+        return True
+    if runtime_core_version is None:
+        from importlib import metadata
+
+        try:
+            runtime_core_version = metadata.version("policyengine-core")
+        except metadata.PackageNotFoundError:
+            return False
+    return certification.certified_for_core_version == runtime_core_version
+
+
 def certify_data_release_compatibility(
     country_id: str,
     runtime_model_version: str,
     runtime_data_build_fingerprint: Optional[str] = None,
+    runtime_core_version: Optional[str] = None,
 ) -> DataCertification:
     country_manifest = get_release_manifest(country_id)
     try:
@@ -428,6 +450,9 @@ def certify_data_release_compatibility(
             if (
                 bundled_certification.certified_for_model_version
                 == runtime_model_version
+                and _runtime_core_is_certified(
+                    bundled_certification, runtime_core_version
+                )
             ):
                 return bundled_certification
             return DataCertification(
@@ -539,6 +564,7 @@ def certify_data_release_compatibility(
         and bundled_certification.certified_for_model_version == runtime_model_version
         and bundled_certification.qualification_pair_id is not None
         and bundled_certification.data_build_id == remote_build_id
+        and _runtime_core_is_certified(bundled_certification, runtime_core_version)
     ):
         return bundled_certification
 
diff --git a/src/policyengine/provenance/qualification_ledger.py b/src/policyengine/provenance/qualification_ledger.py
index ab1835bb..d38d2a63 100644
--- a/src/policyengine/provenance/qualification_ledger.py
+++ b/src/policyengine/provenance/qualification_ledger.py
@@ -130,8 +130,10 @@ def verify_certification_evidence(
 
     Records on any basis other than ``qualified_exact_pair`` need no ledger
     evidence and return no problems. A qualified exact pair needs a
-    promotable receipt for exactly the model wheel, core, data release and
-    dataset bytes the record certifies.
+    promotable receipt for exactly the model wheel (its hash must be stated),
+    core, data release and dataset the record certifies, including the
+    default dataset's reference (repository, path, revision and bytes), which
+    is what the runtime resolves.
     """
 
     certification = record.get("certification") or {}
@@ -154,6 +156,7 @@ def verify_certification_evidence(
     model = record.get("model_package") or {}
     data = record.get("data_package") or {}
     artifact = record.get("certified_data_artifact") or {}
+    reference = (record.get("datasets") or {}).get(record.get("default_dataset")) or {}
     expected: Iterable[tuple[str, Any, Any]] = (
         (
             "model version",
@@ -161,11 +164,7 @@ def verify_certification_evidence(
             certification.get("certified_for_model_version"),
         ),
         ("model version in bundle", pair.model.version, model.get("version")),
-        (
-            "model wheel sha256",
-            pair.model.wheel_sha256,
-            model.get("sha256", pair.model.wheel_sha256),
-        ),
+        ("model wheel sha256", pair.model.wheel_sha256, model.get("sha256")),
         (
             "core version",
             pair.core.version,
@@ -178,7 +177,17 @@ def verify_certification_evidence(
             data.get("release_manifest_revision"),
         ),
         ("default dataset", pair.data.dataset, record.get("default_dataset")),
+        ("certified dataset", pair.data.dataset, artifact.get("dataset")),
         ("dataset sha256", pair.data.dataset_sha256, artifact.get("sha256")),
+        # The reference the runtime actually resolves and downloads.
+        ("dataset reference repo", pair.data.repo_id, reference.get("repo_id")),
+        ("dataset reference path", pair.data.dataset_path, reference.get("path")),
+        (
+            "dataset reference revision",
+            pair.data.dataset_revision,
+            reference.get("revision"),
+        ),
+        ("dataset reference sha256", pair.data.dataset_sha256, reference.get("sha256")),
         ("data build id", pair.data.build_id, certification.get("data_build_id")),
     )
     for label, qualified, certified in expected:
diff --git a/tests/test_qualified_pair_certification.py b/tests/test_qualified_pair_certification.py
index 85028763..b9052c5e 100644
--- a/tests/test_qualified_pair_certification.py
+++ b/tests/test_qualified_pair_certification.py
@@ -114,6 +114,35 @@ def test_stronger_bases_win_over_qualification(self):
         )
         assert basis == "legacy_compatible_model_package"
 
+    @pytest.mark.parametrize(
+        ("model_version", "model_claims"),
+        [("2.122.2", ("==2.122.2",)), ("2.126.8", ("==2.122.2", "==2.126.8"))],
+        ids=["build-time model", "publisher-claimed model"],
+    )
+    def test_an_unclaimed_core_makes_the_basis_the_exact_pair(
+        self, model_version, model_claims
+    ):
+        """Interrupted review of #574: with the model on a stronger basis, a
+        core the publisher never claimed was certified on that basis, and the
+        certificate named no pair, so no evidence was ever required."""
+
+        basis, warnings = validate_release_manifest(
+            _uk_manifest(model_claims=model_claims),
+            "policyengine-uk",
+            model_version,
+            core_version="9.99.0",
+            qualified_pair_id=PAIR_ID,
+        )
+        assert basis == BASIS_QUALIFIED_PAIR
+        assert any("policyengine-core==9.99.0" in item for item in warnings)
+        with pytest.raises(CertificationError, match="policyengine-core 9.99.0"):
+            validate_release_manifest(
+                _uk_manifest(model_claims=model_claims),
+                "policyengine-uk",
+                model_version,
+                core_version="9.99.0",
+            )
+
     def test_qualified_pair_needs_its_core_version(self):
         with pytest.raises(CertificationError, match="core"):
             validate_release_manifest(
@@ -197,7 +226,9 @@ class TestRuntimeAcceptance:
     def setup_method(self):
         get_data_release_manifest.cache_clear()
 
-    def _certify(self, bundled, runtime_model, remote=None, fingerprint=None):
+    def _certify(
+        self, bundled, runtime_model, remote=None, fingerprint=None, core="3.33.0"
+    ):
         manifest = MagicMock(certification=bundled)
         manifest.model_package.name = "policyengine-uk"
         manifest.data_package = MagicMock(
@@ -228,6 +259,7 @@ def _certify(self, bundled, runtime_model, remote=None, fingerprint=None):
                 "uk",
                 runtime_model_version=runtime_model,
                 runtime_data_build_fingerprint=fingerprint,
+                runtime_core_version=core,
             )
 
     def test_online_exact_model_and_build_is_honoured(self):
@@ -246,6 +278,36 @@ def test_online_other_data_build_is_refused(self):
                 remote=_uk_manifest(),
             )
 
+    def test_online_other_core_is_refused(self):
+        """Interrupted review of #574: an exact pair was honoured whatever core ran."""
+
+        with pytest.raises(ValueError, match="not certified"):
+            self._certify(_qualified(), "2.126.8", remote=_uk_manifest(), core="3.34.0")
+
+    def test_offline_other_core_is_not_certified(self):
+        certification = self._certify(_qualified(), "2.126.8", core="3.34.0")
+        assert certification.compatibility_basis == (
+            "unverified_data_release_manifest_unavailable"
+        )
+
+    def test_the_installed_core_is_read_when_none_is_given(self):
+        with patch("importlib.metadata.version", return_value="3.34.0") as installed:
+            with pytest.raises(ValueError, match="not certified"):
+                self._certify(_qualified(), "2.126.8", remote=_uk_manifest(), core=None)
+        installed.assert_called_with("policyengine-core")
+
+    def test_other_bases_make_no_runtime_core_claim(self):
+        legacy = DataCertification(
+            compatibility_basis="legacy_compatible_model_package",
+            certified_for_model_version="2.126.8",
+            certified_for_core_version="3.33.0",
+            data_build_id="policyengine-uk-data-1.58.0",
+        )
+        assert (
+            self._certify(legacy, "2.126.8", core="3.34.0").compatibility_basis
+            == "legacy_compatible_model_package"
+        )
+
     def test_offline_fingerprint_difference_is_expected(self):
         certification = self._certify(
             _qualified(), "2.126.8", fingerprint="sha256:runtime"
@@ -275,7 +337,18 @@ def _record_for(receipt):
             "release_manifest_revision": pair.data.release_manifest_revision,
         },
         "default_dataset": pair.data.dataset,
-        "certified_data_artifact": {"sha256": pair.data.dataset_sha256},
+        "certified_data_artifact": {
+            "dataset": pair.data.dataset,
+            "sha256": pair.data.dataset_sha256,
+        },
+        "datasets": {
+            pair.data.dataset: {
+                "repo_id": pair.data.repo_id,
+                "path": pair.data.dataset_path,
+                "revision": pair.data.dataset_revision,
+                "sha256": pair.data.dataset_sha256,
+            }
+        },
     }
 
 
@@ -298,6 +371,31 @@ def test_matching_promotable_receipt_is_sufficient():
     assert verify_certification_evidence(_record_for(receipt), receipt) == []
 
 
+REFERENCE_FIELDS = ["repo_id", "path", "revision", "sha256"]
+
+
+@pytest.mark.parametrize("field", REFERENCE_FIELDS)
+def test_the_dataset_reference_the_runtime_resolves_is_evidence_too(field):
+    """Interrupted review of #574: a record pointing its default dataset at
+    another repository, path, revision or file verified against the receipt."""
+
+    receipt = make_receipt()
+    record = _record_for(receipt)
+    record["datasets"][receipt.pair.data.dataset][field] = "f" * 64
+    problems = verify_certification_evidence(record, receipt)
+    assert any("dataset reference" in problem for problem in problems)
+    del record["datasets"][receipt.pair.data.dataset]
+    assert verify_certification_evidence(record, receipt)
+
+
+def test_a_record_without_the_model_wheel_hash_is_refused():
+    receipt = make_receipt()
+    record = _record_for(receipt)
+    del record["model_package"]["sha256"]
+    problems = verify_certification_evidence(record, receipt)
+    assert any("model wheel sha256" in problem for problem in problems)
+
+
 def test_missing_or_unpromotable_receipt_is_refused():
     receipt = make_receipt()
     record = _record_for(receipt)
@@ -315,6 +413,7 @@ def test_missing_or_unpromotable_receipt_is_refused():
     ("data_package", "version"),
     ("data_package", "release_manifest_revision"),
     ("certified_data_artifact", "sha256"),
+    ("certified_data_artifact", "dataset"),
 ]
 
 

From a17f801297ca884cf134f0ab3b085516b09056bf Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 20:37:40 -0400
Subject: [PATCH 16/45] Close promotion and ledger holes found by review

- A candidate branch names its pair id, so two pairs that share model and
  data versions (another core, another wheel) can never share a branch.
  Before, a qualified pair could ready an incomplete pair's branch.
- Promotion readies a branch only while its pull request is at exactly
  the commit the qualification ran on, and an automatic merge passes
  --match-head-commit, so the replayed and tested bytes are the promoted
  bytes.
- A forced re-qualification stages a new attempt key when one already
  exists for that base, instead of being stopped by the duplicate guard.
- The ledger publish retry replays its commit with cherry-pick on the
  fetched tip, so two runs that both create the ledger no longer fail on
  HEAD~1; a test runs that race against a real bare repository.

Refs #573

Co-Authored-By: Claude Opus 5.5 
---
 .github/qualification-ledger.sh               |  26 ++--
 scripts/check_uk_candidate.py                 |  32 +++--
 .../provenance/uk_qualification.py            |  81 ++++++++++++-
 tests/test_qualification_ledger_script.py     | 111 ++++++++++++++++++
 tests/test_uk_qualification_pipeline.py       |  99 +++++++++++++++-
 5 files changed, 327 insertions(+), 22 deletions(-)
 create mode 100644 tests/test_qualification_ledger_script.py

diff --git a/.github/qualification-ledger.sh b/.github/qualification-ledger.sh
index 6a1bff7c..b42186d6 100755
--- a/.github/qualification-ledger.sh
+++ b/.github/qualification-ledger.sh
@@ -8,7 +8,8 @@
 # The ledger is an orphan branch that only grows: each candidate pair writes
 # its own directory, so concurrent publishes never touch the same file and a
 # rejected push is retried by replaying the single new commit on the latest
-# tip.
+# tip. The new commit may be the branch's first (two runs can both find no
+# ledger yet), so it is replayed with cherry-pick, which needs no parent.
 set -euo pipefail
 
 BRANCH="${LEDGER_BRANCH:-uk-qualification-ledger}"
@@ -44,17 +45,28 @@ README
       echo "Ledger unchanged."
       exit 0
     fi
-    git -c user.name="policyengine-qualification[bot]" \
-        -c user.email="qualification@policyengine.org" \
-        commit --quiet -m "$message"
+    identity=(-c user.name="policyengine-qualification[bot]"
+              -c user.email="qualification@policyengine.org")
+    git "${identity[@]}" commit --quiet -m "$message"
+    new_commit="$(git rev-parse HEAD)"
+    delay="${LEDGER_RETRY_DELAY:-5}"
     for attempt in 1 2 3 4 5 6; do
       if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then
         echo "Published ledger: $message"
         exit 0
       fi
-      git fetch --quiet origin "$BRANCH"
-      git rebase --quiet --onto FETCH_HEAD HEAD~1 HEAD
-      sleep $((attempt * 5))
+      # Someone else published first: replay this one commit on their tip.
+      if ! git fetch --quiet origin "$BRANCH"; then
+        sleep $((attempt * delay))
+        continue
+      fi
+      git reset --quiet --hard FETCH_HEAD
+      if ! git "${identity[@]}" cherry-pick --allow-empty "$new_commit" >/dev/null; then
+        git cherry-pick --abort || true
+        echo "::error::The ledger commit conflicts with a concurrent publish."
+        exit 1
+      fi
+      sleep $((attempt * delay))
     done
     echo "::error::Could not publish the qualification ledger after 6 attempts."
     exit 1
diff --git a/scripts/check_uk_candidate.py b/scripts/check_uk_candidate.py
index 000b4237..59a281fc 100644
--- a/scripts/check_uk_candidate.py
+++ b/scripts/check_uk_candidate.py
@@ -63,6 +63,7 @@
     WheelFile,
     accept_review,
     attempt_is_waiting_for_replay,
+    attempt_key,
     build_replay_request,
     candidate_action,
     candidate_branch,
@@ -218,6 +219,12 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         base_commit=base_commit,
         force=args.force,
     )
+    key = attempt_key(
+        resolved.pair,
+        Path(args.ledger) if args.ledger else None,
+        base_commit=base_commit,
+        force=args.force,
+    )
     payload = {
         "pair": resolved.pair.canonical_payload(),
         "pair_id": resolved.pair.pair_id,
@@ -226,7 +233,7 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         "manifest_uri": resolved.manifest_uri,
         "model_requires_core": resolved.model_requires_core,
         "base_commit": base_commit,
-        "attempt_key": base_commit[:12],
+        "attempt_key": key,
         "branch": candidate_branch(resolved.pair),
         "action": action,
         "reason": reason,
@@ -241,7 +248,7 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         pair_id=resolved.pair.pair_id,
         branch=candidate_branch(resolved.pair),
         base_commit=base_commit,
-        attempt_key=base_commit[:12],
+        attempt_key=key,
     )
     return 0
 
@@ -404,7 +411,9 @@ def cmd_waiting(args: argparse.Namespace) -> int:
     return 0
 
 
-def _open_candidate_branches() -> list[str]:
+def _open_candidate_branches() -> dict[str, str]:
+    """Open candidate branches and the commit each one's pull request is at."""
+
     listing = subprocess.run(
         [
             "gh",
@@ -417,23 +426,26 @@ def _open_candidate_branches() -> list[str]:
             "--search",
             "head:candidate/uk/",
             "--json",
-            "headRefName",
+            "headRefName,headRefOid",
         ],
         check=True,
         capture_output=True,
         text=True,
     ).stdout
-    return [item["headRefName"] for item in json.loads(listing)]
+    return {item["headRefName"]: item["headRefOid"] for item in json.loads(listing)}
 
 
 def cmd_promote(args: argparse.Namespace) -> int:
     bundle = json.loads(BUNDLE_PATH.read_text())
     receipts = latest_receipts(Path(args.ledger))
-    branches = _open_candidate_branches() if args.apply else []
+    branches = _open_candidate_branches() if args.apply else {}
     plan = plan_promotion(receipts, bundle, branches)
     print(f"promotion: {plan.reason}")
     if plan.target is not None:
-        print(f"target {plan.ready_branch} (pair {plan.target.pair_id[:12]})")
+        print(
+            f"target {plan.ready_branch or 'not promotable now'} "
+            f"(pair {plan.target.pair_id[:12]}, commit {plan.ready_commit})"
+        )
     for branch in plan.close_branches:
         print(f"superseded {branch}")
     if not args.apply:
@@ -452,12 +464,14 @@ def cmd_promote(args: argparse.Namespace) -> int:
             ],
             check=False,
         )
-    if plan.ready_branch is not None and plan.ready_branch in branches:
+    if plan.ready_branch is not None and plan.ready_commit is not None:
         subprocess.run(
             ["gh", "pr", "ready", plan.ready_branch, "--repo", LEDGER_REPOSITORY],
             check=False,
         )
         if config()["promotion"]["automatic"]:
+            # GitHub refuses the merge if the branch moved off the qualified
+            # commit between the plan and the merge.
             subprocess.run(
                 [
                     "gh",
@@ -468,6 +482,8 @@ def cmd_promote(args: argparse.Namespace) -> int:
                     LEDGER_REPOSITORY,
                     "--auto",
                     "--squash",
+                    "--match-head-commit",
+                    plan.ready_commit,
                 ],
                 check=False,
             )
diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index 8e139728..ae83d374 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -437,7 +437,46 @@ def rewrite_certified_constants(
 
 
 def candidate_branch(pair: CandidatePair) -> str:
-    return f"candidate/uk/{pair.model.version}-{pair.data.release_version}"
+    """The pair's own branch.
+
+    The pair id is part of the name: two pairs that share model and data
+    versions (another core, another wheel, re-published bytes) must never
+    share a branch, or one pair's qualification could promote the other's
+    commit.
+    """
+
+    return (
+        f"candidate/uk/{pair.model.version}-{pair.data.release_version}"
+        f"-{pair.pair_id[:12]}"
+    )
+
+
+def attempt_key(
+    pair: CandidatePair,
+    ledger_root: Optional[Path],
+    *,
+    base_commit: str,
+    force: bool = False,
+) -> str:
+    """The ledger key of the attempt a qualification run would stage.
+
+    One attempt per base commit, so concurrent runs for the same pair and
+    base deduplicate. A forced run after such an attempt gets the next free
+    key instead, so it stages a fresh attempt and is not mistaken for the
+    old one.
+    """
+
+    key = base_commit[:12]
+    if not force or ledger_root is None:
+        return key
+    if not attempt_directory(ledger_root, "uk", pair.pair_id, key).exists():
+        return key
+    repeat = 2
+    while attempt_directory(
+        ledger_root, "uk", pair.pair_id, f"{key}-{repeat}"
+    ).exists():
+        repeat += 1
+    return f"{key}-{repeat}"
 
 
 def changelog_fragment(pair: CandidatePair, basis_note: str) -> str:
@@ -889,14 +928,23 @@ class PromotionPlan:
     ready_branch: Optional[str]
     close_branches: list[str] = field(default_factory=list)
     reason: str = ""
+    #: The qualified commit the ready branch must still be at when promoted.
+    ready_commit: Optional[str] = None
 
 
 def plan_promotion(
     receipts: Iterable[QualificationReceipt],
     bundle: Mapping[str, Any],
-    open_candidate_branches: Iterable[str],
+    open_candidate_branches: Mapping[str, str],
 ) -> PromotionPlan:
-    """What to do with candidate PRs given the ledger and ``main``'s certificate."""
+    """What to do with candidate PRs given the ledger and ``main``'s certificate.
+
+    ``open_candidate_branches`` maps each open candidate branch to its head
+    commit. The target's branch is readied only while its head is exactly
+    the commit the target's qualification ran on
+    (``receipt.harness.git_commit``): the replayed and tested bytes are the
+    promoted bytes. A branch that moved since is left alone and reported.
+    """
 
     receipts = list(receipts)
     current = certified_order_key(bundle)
@@ -920,9 +968,34 @@ def plan_promotion(
             close_branches=sorted(close),
             reason=f"no promotable pair advances {current}",
         )
+    branch = candidate_branch(target.pair)
+    qualified_commit = target.harness.git_commit
+    head = open_candidate_branches.get(branch)
+    if head is None:
+        return PromotionPlan(
+            target=target,
+            ready_branch=None,
+            close_branches=sorted(close),
+            reason=(
+                f"{target.pair.order_key} advances {current}, but its branch "
+                f"{branch} has no open pull request"
+            ),
+        )
+    if head != qualified_commit:
+        return PromotionPlan(
+            target=target,
+            ready_branch=None,
+            close_branches=sorted(close),
+            reason=(
+                f"{target.pair.order_key} advances {current}, but {branch} is at "
+                f"{head[:12]}, not the qualified commit {qualified_commit[:12]}; "
+                "nothing is promoted"
+            ),
+        )
     return PromotionPlan(
         target=target,
-        ready_branch=candidate_branch(target.pair),
+        ready_branch=branch,
+        ready_commit=qualified_commit,
         close_branches=sorted(close),
         reason=f"{target.pair.order_key} advances {current}",
     )
diff --git a/tests/test_qualification_ledger_script.py b/tests/test_qualification_ledger_script.py
new file mode 100644
index 00000000..5e71953f
--- /dev/null
+++ b/tests/test_qualification_ledger_script.py
@@ -0,0 +1,111 @@
+"""The ledger publish script (.github/qualification-ledger.sh) under concurrency.
+
+Invariant: publishes from concurrent runs never lose evidence. Each run's new
+directory ends up on the ledger branch, including when both runs found no
+ledger yet and each made the branch's first commit.
+"""
+
+from __future__ import annotations
+
+import os
+import shutil
+import subprocess
+from pathlib import Path
+
+import pytest
+
+SCRIPT = Path(__file__).resolve().parents[1] / ".github" / "qualification-ledger.sh"
+
+pytestmark = pytest.mark.skipif(shutil.which("git") is None, reason="needs git")
+
+
+def _run(*args, cwd, check=True):
+    env = {
+        **os.environ,
+        "GIT_AUTHOR_NAME": "test",
+        "GIT_AUTHOR_EMAIL": "test@example.org",
+        "GIT_COMMITTER_NAME": "test",
+        "GIT_COMMITTER_EMAIL": "test@example.org",
+        "GIT_TERMINAL_PROMPT": "0",
+        "LEDGER_RETRY_DELAY": "0",
+    }
+    return subprocess.run(
+        args,
+        cwd=cwd,
+        env=env,
+        check=check,
+        text=True,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.STDOUT,
+    )
+
+
+def _clone(root: Path, origin: Path, name: str) -> Path:
+    clone = root / name
+    _run(
+        "git", "clone", "--quiet", "--branch", "main", str(origin), str(clone), cwd=root
+    )
+    return clone
+
+
+def _origin(root: Path) -> Path:
+    origin = root / "origin.git"
+    _run("git", "init", "--quiet", "--bare", "-b", "main", str(origin), cwd=root)
+    seed = root / "seed"
+    _run("git", "clone", "--quiet", str(origin), str(seed), cwd=root)
+    (seed / "seed").write_text("seed")
+    _run("git", "add", "seed", cwd=seed)
+    _run("git", "commit", "--quiet", "-m", "seed", cwd=seed)
+    _run("git", "push", "--quiet", "origin", "HEAD:refs/heads/main", cwd=seed)
+    return origin
+
+
+def _ledger_files(origin: Path) -> set[str]:
+    listing = _run(
+        "git", "ls-tree", "-r", "--name-only", "uk-qualification-ledger", cwd=origin
+    )
+    return set(listing.stdout.split())
+
+
+@pytest.mark.parametrize("ledger_exists", [False, True])
+def test_concurrent_publishes_keep_both_runs_evidence(tmp_path, ledger_exists):
+    """Interrupted review of #574: the second first-ever publish failed on HEAD~1."""
+
+    origin = _origin(tmp_path)
+    if ledger_exists:
+        first = _clone(tmp_path, origin, "first")
+        _run("bash", str(SCRIPT), "checkout", "ledger", cwd=first)
+        (first / "ledger" / "existing").write_text("existing")
+        _run("bash", str(SCRIPT), "publish", "ledger", "existing", cwd=first)
+    clones = []
+    for name in ("a", "b"):
+        clone = _clone(tmp_path, origin, name)
+        _run("bash", str(SCRIPT), "checkout", "ledger", cwd=clone)
+        (clone / "ledger" / "uk" / name).mkdir(parents=True)
+        (clone / "ledger" / "uk" / name / "receipt.json").write_text(name)
+        clones.append(clone)
+    for clone, name in zip(clones, ("a", "b")):
+        result = _run(
+            "bash",
+            str(SCRIPT),
+            "publish",
+            "ledger",
+            f"attempt {name}",
+            cwd=clone,
+            check=False,
+        )
+        assert result.returncode == 0, result.stdout
+    files = _ledger_files(origin)
+    assert {"uk/a/receipt.json", "uk/b/receipt.json"} <= files
+    if ledger_exists:
+        assert "existing" in files
+
+
+def test_an_unchanged_ledger_publishes_nothing(tmp_path):
+    origin = _origin(tmp_path)
+    clone = _clone(tmp_path, origin, "a")
+    _run("bash", str(SCRIPT), "checkout", "ledger", cwd=clone)
+    (clone / "ledger" / "x").write_text("x")
+    _run("bash", str(SCRIPT), "publish", "ledger", "first", cwd=clone)
+    again = _run("bash", str(SCRIPT), "publish", "ledger", "again", cwd=clone)
+    assert "Ledger unchanged." in again.stdout
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index ee24ac87..41086dc4 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -20,6 +20,7 @@
 import json
 import shutil
 from pathlib import Path
+from types import SimpleNamespace
 
 import jsonschema
 import pytest
@@ -393,18 +394,110 @@ def test_promotion_plan():
         gate_results=gates(replay="fail"),
     )
     stale = make_receipt(pair=make_pair(model="2.0.0", data="1.0.0", core="3.0.0"))
-    branches = [candidate_branch(r.pair) for r in (newest, older, rejected, stale)] + [
-        "candidate/uk/unknown"
-    ]
+    branches = {
+        candidate_branch(r.pair): r.harness.git_commit
+        for r in (newest, older, rejected, stale)
+    }
+    branches["candidate/uk/unknown"] = "0" * 40
     plan = plan_promotion([newest, older, rejected, stale], BUNDLE, branches)
     assert plan.target == newest
     assert plan.ready_branch == candidate_branch(newest.pair)
+    assert plan.ready_commit == newest.harness.git_commit
     assert plan.close_branches == sorted(
         [candidate_branch(older.pair), candidate_branch(stale.pair)]
     )
     assert candidate_branch(rejected.pair) not in plan.close_branches
 
 
+def _promotable_pair_and_branch(core=None):
+    current = BUNDLE["data_releases"]["uk"]["data_package"]["version"]
+    core = core or BUNDLE["packages"]["policyengine-core"]["version"]
+    return make_pair(model="2.200.0", data=current, core=core)
+
+
+def test_pairs_that_share_versions_never_share_a_branch():
+    """Interrupted review of #574: a qualified pair readied the branch of an
+    incomplete pair with the same model and data but another core."""
+
+    qualified_pair = _promotable_pair_and_branch()
+    other_core = _promotable_pair_and_branch(core="3.99.0")
+    assert qualified_pair.pair_id != other_core.pair_id
+    assert candidate_branch(qualified_pair) != candidate_branch(other_core)
+    assert qualified_pair.pair_id[:12] in candidate_branch(qualified_pair)
+    qualified = make_receipt(pair=qualified_pair)
+    incomplete = make_receipt(pair=other_core, gate_results=gates(replay="unavailable"))
+    plan = plan_promotion(
+        [qualified, incomplete],
+        BUNDLE,
+        {candidate_branch(other_core): incomplete.harness.git_commit},
+    )
+    assert plan.target == qualified
+    assert plan.ready_branch is None
+    assert "has no open pull request" in plan.reason
+
+
+def test_a_branch_that_moved_off_the_qualified_commit_is_not_promoted():
+    """The replayed and tested commit must be the promoted commit."""
+
+    qualified = make_receipt(pair=_promotable_pair_and_branch())
+    branch = candidate_branch(qualified.pair)
+    plan = plan_promotion([qualified], BUNDLE, {branch: "f" * 40})
+    assert plan.target == qualified and plan.ready_branch is None
+    assert "not the qualified commit" in plan.reason
+    plan = plan_promotion([qualified], BUNDLE, {branch: qualified.harness.git_commit})
+    assert plan.ready_branch == branch
+
+
+def test_promote_readies_and_merges_only_the_qualified_commit(monkeypatch, tmp_path):
+    import argparse
+    import importlib.util
+
+    qualified = make_receipt(pair=_promotable_pair_and_branch())
+    branch = candidate_branch(qualified.pair)
+    spec = importlib.util.spec_from_file_location(
+        "check_uk_candidate_for_test",
+        Path(__file__).resolve().parents[1] / "scripts" / "check_uk_candidate.py",
+    )
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+    calls = []
+    monkeypatch.setattr(cli, "latest_receipts", lambda root: [qualified])
+    monkeypatch.setattr(
+        cli, "subprocess", SimpleNamespace(run=lambda argv, **k: calls.append(argv))
+    )
+    monkeypatch.setattr(cli, "config", lambda: {"promotion": {"automatic": True}})
+    monkeypatch.setattr(cli, "_open_candidate_branches", lambda: {branch: "f" * 40})
+    assert cli.cmd_promote(argparse.Namespace(ledger=str(tmp_path), apply=True)) == 0
+    assert calls == []
+    monkeypatch.setattr(
+        cli,
+        "_open_candidate_branches",
+        lambda: {branch: qualified.harness.git_commit},
+    )
+    assert cli.cmd_promote(argparse.Namespace(ledger=str(tmp_path), apply=True)) == 0
+    assert calls[0][:3] == ["gh", "pr", "ready"] and calls[0][3] == branch
+    assert calls[1][-2:] == ["--match-head-commit", qualified.harness.git_commit]
+
+
+def test_a_forced_rerun_stages_a_new_attempt(tmp_path):
+    """Interrupted review of #574: a forced run reused the existing attempt key,
+    so the workflow's duplicate guard stopped it."""
+
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import attempt_key
+
+    pair = _promotable_pair_and_branch()
+    base = "a" * 40
+    assert attempt_key(pair, tmp_path, base_commit=base, force=True) == base[:12]
+    attempt_directory(tmp_path, "uk", pair.pair_id, base[:12]).mkdir(parents=True)
+    assert attempt_key(pair, tmp_path, base_commit=base) == base[:12]
+    assert attempt_key(pair, tmp_path, base_commit=base, force=True) == f"{base[:12]}-2"
+    attempt_directory(tmp_path, "uk", pair.pair_id, f"{base[:12]}-2").mkdir(
+        parents=True
+    )
+    assert attempt_key(pair, tmp_path, base_commit=base, force=True) == f"{base[:12]}-3"
+
+
 # --- Attempt lifecycle -----------------------------------------------------------------
 
 

From 0d5cc12f181be2ee8f2f64d8a874cf6fb2c00a70 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Sun, 11 Oct 2026 23:24:05 -0400
Subject: [PATCH 17/45] Pin W3's metrics tool at 9b33fe19f

policyengine-uk#2335 moved one commit: the tool digest is now taken when
the module loads, so a result is stamped with the code that produced it.
standard_reforms.yaml is byte-identical and the report format unchanged,
so the fixtures stay the bd8bff74c run; the README says why. Also sorts
one import block.

Co-Authored-By: Claude Opus 5.5 
---
 scripts/release_consumers.py                |  4 +++-
 src/policyengine/data/qualification/uk.json |  2 +-
 tests/fixtures/uk_metrics/README.md         | 11 ++++++++---
 3 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/scripts/release_consumers.py b/scripts/release_consumers.py
index 5e105cf4..3eefa409 100644
--- a/scripts/release_consumers.py
+++ b/scripts/release_consumers.py
@@ -29,7 +29,9 @@
 
 import requests  # noqa: E402
 
-from policyengine.provenance.qualification_ledger import fetch_ledger_receipt  # noqa: E402
+from policyengine.provenance.qualification_ledger import (
+    fetch_ledger_receipt,  # noqa: E402
+)
 from policyengine.provenance.uk_qualification import (  # noqa: E402
     release_dispatch_payload,
     released_bundle_request,
diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index 3c60ad51..00281419 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,7 +12,7 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "bd8bff74c0baea19c09eedf9ce1391d598d2ffaf",
+      "commit": "9b33fe19f80676fc5b81d2d80b36072e1c2fc1df",
       "path": "policyengine_uk/utils/aggregate_impact",
       "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
     },
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index a5976b28..f438a64c 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -3,9 +3,14 @@
 Both files come from PolicyEngine/policyengine-uk's aggregate-impact tool
 (`policyengine_uk/utils/aggregate_impact/`, policyengine-uk#2335), which the
 qualification config pins at commit
-`bd8bff74c0baea19c09eedf9ce1391d598d2ffaf`.
-`tests/test_uk_candidate_gates.py` reads them. Refresh them from the newly
-pinned commit; never edit them by hand.
+`9b33fe19f80676fc5b81d2d80b36072e1c2fc1df`. They were produced at its parent,
+`bd8bff74c0baea19c09eedf9ce1391d598d2ffaf`; the pinned commit changes only
+when the tool digest is taken (at module load rather than at the end of a
+run), so `standard_reforms.yaml` is byte-identical there and the report format
+is unchanged. A report from the pinned commit differs only in
+`metrics_version`, which the gate compares between the two pairs' reports,
+never against this file. `tests/test_uk_candidate_gates.py` reads them.
+Refresh them when a pin changes the report; never edit them by hand.
 
 - `standard_reforms.yaml`: the tool's standard reform set, copied unchanged.
   Ten reforms, each with the model variable it must move, the direction and

From 23698f42ec71a20682f3b41f064ff5ada3a2feee Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:29:23 -0400
Subject: [PATCH 18/45] Enforce the qualified core before online compatibility
 acceptance

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/manifest.py    | 13 ++++++
 tests/test_qualified_pair_certification.py | 54 ++++++++++++++++++++++
 2 files changed, 67 insertions(+)

diff --git a/src/policyengine/provenance/manifest.py b/src/policyengine/provenance/manifest.py
index 600d0ac5..8f1a6446 100644
--- a/src/policyengine/provenance/manifest.py
+++ b/src/policyengine/provenance/manifest.py
@@ -469,6 +469,19 @@ def certify_data_release_compatibility(
                 certified_by=bundled_certification.certified_by,
             )
         raise exc
+
+    # An exact-pair certificate also restricts the core when the remote
+    # manifest offers a stronger model or fingerprint compatibility basis.
+    # Enforce that restriction before any online acceptance path can return.
+    bundled_certification = country_manifest.certification
+    if bundled_certification is not None and not _runtime_core_is_certified(
+        bundled_certification, runtime_core_version
+    ):
+        raise ValueError(
+            "Data release manifest is not certified for the runtime core version "
+            f"{runtime_core_version} in country '{country_id}'; the exact pair "
+            f"requires {bundled_certification.certified_for_core_version}."
+        )
     built_with_model = (
         data_release_manifest.build.built_with_model_package
         if data_release_manifest.build is not None
diff --git a/tests/test_qualified_pair_certification.py b/tests/test_qualified_pair_certification.py
index b9052c5e..fc0f603c 100644
--- a/tests/test_qualified_pair_certification.py
+++ b/tests/test_qualified_pair_certification.py
@@ -284,6 +284,60 @@ def test_online_other_core_is_refused(self):
         with pytest.raises(ValueError, match="not certified"):
             self._certify(_qualified(), "2.126.8", remote=_uk_manifest(), core="3.34.0")
 
+    @pytest.mark.parametrize(
+        ("runtime_model", "fingerprint", "claims", "expected_basis"),
+        [
+            ("2.122.2", None, (), "exact_build_model_version"),
+            (
+                "2.126.8",
+                "sha256:build",
+                (),
+                "matching_data_build_fingerprint",
+            ),
+            (
+                "2.126.8",
+                None,
+                ("==2.126.8",),
+                "legacy_compatible_model_package",
+            ),
+        ],
+        ids=["build-model", "fingerprint", "publisher-claim"],
+    )
+    def test_online_stronger_basis_cannot_bypass_qualified_core(
+        self, runtime_model, fingerprint, claims, expected_basis
+    ):
+        remote = _uk_manifest(model_claims=claims)
+        bundled = _qualified(model=runtime_model)
+        assert (
+            self._certify(
+                bundled, runtime_model, remote=remote, fingerprint=fingerprint
+            ).compatibility_basis
+            == expected_basis
+        )
+        with pytest.raises(ValueError, match="not certified"):
+            self._certify(
+                bundled,
+                runtime_model,
+                remote=remote,
+                fingerprint=fingerprint,
+                core="99.0.0",
+            )
+
+    def test_online_build_model_requires_installed_qualified_core(self):
+        from importlib.metadata import PackageNotFoundError
+
+        with patch(
+            "importlib.metadata.version",
+            side_effect=PackageNotFoundError("policyengine-core"),
+        ):
+            with pytest.raises(ValueError, match="not certified"):
+                self._certify(
+                    _qualified(model="2.122.2"),
+                    "2.122.2",
+                    remote=_uk_manifest(),
+                    core=None,
+                )
+
     def test_offline_other_core_is_not_certified(self):
         certification = self._certify(_qualified(), "2.126.8", core="3.34.0")
         assert certification.compatibility_basis == (

From 537c0c1369ee40624ea4728bd761a3a9faf727e0 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:29:24 -0400
Subject: [PATCH 19/45] Require exact replay wheel evidence and record baseline
 wheel identity

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/qualification.py | 17 +++++-
 tests/test_qualification_contracts.py        | 59 +++++++++++++++++++-
 2 files changed, 71 insertions(+), 5 deletions(-)

diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index 8ed36430..45a04ccf 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -219,6 +219,9 @@ class PreviousCertificate(_Contract):
     data_release_version: str
     dataset_sha256: str = Field(pattern=SHA256_PATTERN)
     certificate_sha256: str = Field(pattern=SHA256_PATTERN)
+    qualification_pair_id: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
+    model_wheel_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
+    core_wheel_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
 
 
 class ReplayReference(_Contract):
@@ -811,7 +814,11 @@ def evaluate_replay_receipt(
         "policyengine": (
             execution.packages.policyengine,
             candidate.policyengine.version,
-            None,
+            (
+                candidate.policyengine.source.pypi.wheel_sha256
+                if candidate.policyengine.source.pypi is not None
+                else None
+            ),
         ),
         "policyengine-uk": (
             execution.packages.policyengine_uk,
@@ -827,8 +834,12 @@ def evaluate_replay_receipt(
     for name, (installed, version, wheel) in packages.items():
         if installed.version != version:
             mismatches.append(f"{name} {installed.version} ran, not {version}")
-        if wheel is not None and installed.wheel_sha256 not in (None, wheel):
-            mismatches.append(f"{name} wheel hash differs from the request")
+        if wheel is not None and installed.wheel_sha256 != wheel:
+            mismatches.append(
+                f"{name} wheel hash is missing from the receipt"
+                if installed.wheel_sha256 is None
+                else f"{name} wheel hash differs from the request"
+            )
     if (
         execution.packaged_bundle_manifest_sha256
         != candidate.policyengine.packaged_bundle_manifest_sha256
diff --git a/tests/test_qualification_contracts.py b/tests/test_qualification_contracts.py
index 92975466..642d6747 100644
--- a/tests/test_qualification_contracts.py
+++ b/tests/test_qualification_contracts.py
@@ -441,10 +441,24 @@ def _gate(receipt_doc, request=None, status=None):
     )
 
 
+def _with_requested_wheels(doc):
+    """Add artifact evidence omitted by the scorecard's synthetic golden fixture."""
+
+    requested = golden("qualification_request_golden")["candidate"]
+    for package, request_key in (
+        ("policyengine-uk", "policyengine_uk"),
+        ("policyengine-core", "policyengine_core"),
+    ):
+        doc["execution"]["packages"][package]["wheel_sha256"] = requested[request_key][
+            "wheel_sha256"
+        ]
+    return doc
+
+
 def _with_counts(sealed=True, **counts):
     """The golden receipt with these flag counts and one flagged row per flag."""
 
-    doc = copy.deepcopy(golden("replay_receipt_golden"))
+    doc = _with_requested_wheels(copy.deepcopy(golden("replay_receipt_golden")))
     base = {key: 0 for key in doc["diff"]["flag_counts"]}
     base.update(counts)
     doc["diff"]["flag_counts"] = base
@@ -458,7 +472,8 @@ def _with_counts(sealed=True, **counts):
 
 
 def test_golden_receipt_fails_on_its_structural_flag():
-    gate = _gate(golden("replay_receipt_golden"))
+    doc = _with_requested_wheels(copy.deepcopy(golden("replay_receipt_golden")))
+    gate = _gate(_sealed(doc))
     assert gate.status == "fail"
     assert "structural" in gate.summary
 
@@ -585,6 +600,46 @@ def test_execution_of_other_artifacts_fails():
         assert _gate(_sealed(doc)).status == "fail"
 
 
+@pytest.mark.parametrize("package", ["policyengine-uk", "policyengine-core"])
+@pytest.mark.parametrize("wheel_sha256", [None, "0" * 64])
+def test_replay_requires_exact_country_and_core_wheels(package, wheel_sha256):
+    doc = _clean_receipt()
+    installed = doc["execution"]["packages"][package]
+    if wheel_sha256 is None:
+        installed.pop("wheel_sha256")
+    else:
+        installed["wheel_sha256"] = wheel_sha256
+    gate = _gate(_sealed(doc))
+    assert gate.status == "fail"
+    assert f"{package} wheel hash" in gate.summary
+
+
+@pytest.mark.parametrize("wheel_sha256", [None, "0" * 64])
+def test_released_bundle_replay_requires_requested_wrapper_wheel(wheel_sha256):
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["kind"] = "released_bundle"
+    raw["candidate"]["policyengine"]["source"] = {"pypi": {"wheel_sha256": "a" * 64}}
+    request = ReplayQualificationRequest.model_validate(raw)
+    doc = _clean_receipt()
+    doc["request_id"] = request.request_id
+    if wheel_sha256 is not None:
+        doc["execution"]["packages"]["policyengine"]["wheel_sha256"] = wheel_sha256
+    gate = _gate(_sealed(doc), request=request)
+    assert gate.status == "fail"
+    assert "policyengine wheel hash" in gate.summary
+
+
+def test_released_bundle_replay_accepts_exact_requested_wrapper_wheel():
+    raw = copy.deepcopy(golden("qualification_request_golden"))
+    raw["kind"] = "released_bundle"
+    raw["candidate"]["policyengine"]["source"] = {"pypi": {"wheel_sha256": "a" * 64}}
+    request = ReplayQualificationRequest.model_validate(raw)
+    doc = _clean_receipt()
+    doc["request_id"] = request.request_id
+    doc["execution"]["packages"]["policyengine"]["wheel_sha256"] = "a" * 64
+    assert _gate(_sealed(doc), request=request).status == "pass"
+
+
 def test_unbound_receipts_fail():
     sealed = _with_counts()
     tampered = copy.deepcopy(sealed)

From 3d19e3c59057a0cad998da7f7d03eabe8099175f Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:29:30 -0400
Subject: [PATCH 20/45] Prepare exact UK candidate sidecars and keep staged
 receipts ordered and immutable

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 scripts/generate_trace_tros.py                |  23 +-
 .../provenance/uk_qualification.py            | 124 ++++++-
 tests/test_uk_qualification_pipeline.py       | 321 ++++++++++++++++++
 3 files changed, 461 insertions(+), 7 deletions(-)

diff --git a/scripts/generate_trace_tros.py b/scripts/generate_trace_tros.py
index a9541b46..b34562f8 100644
--- a/scripts/generate_trace_tros.py
+++ b/scripts/generate_trace_tros.py
@@ -76,7 +76,17 @@ def _validate_reviewed_inputs(
     ):
         raise ValueError(f"{prefix} requires certification for the pinned model")
     validate_release_manifest(
-        data, country.model_package.name, country.model_package.version
+        data,
+        country.model_package.name,
+        country.model_package.version,
+        # Revalidate the certificate's exact qualification context, including
+        # qualification-only models/cores. Never substitute a publisher range.
+        core_version=country.certification.certified_for_core_version,
+        qualified_pair_id=(
+            country.certification.qualification_pair_id
+            if country.certification.compatibility_basis == "qualified_exact_pair"
+            else None
+        ),
     )
     certified = country.certified_data_artifact
     artifact = data.artifacts.get(certified.dataset) if certified else None
@@ -127,6 +137,17 @@ def _validate_runtime_model(bundle: dict, country: CountryReleaseManifest) -> No
     component = bundle.get("packages", {}).get(key, {})
     model = country.model_package
     prefix = f"{country.country_id}: strict TRACE release"
+    certification = country.certification
+    if certification and certification.compatibility_basis == "qualified_exact_pair":
+        core = bundle.get("packages", {}).get("policyengine-core", {})
+        if (
+            not certification.qualification_pair_id
+            or not certification.certified_for_core_version
+            or core.get("version") != certification.certified_for_core_version
+        ):
+            raise ValueError(
+                f"{prefix}: runtime core differs from the qualified exact pair"
+            )
     if (
         model.name != key
         or component.get("name") != model.name
diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index ae83d374..7ee5e9b0 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -337,6 +337,11 @@ def previous_certificate(bundle: Mapping[str, Any]) -> PreviousCertificate:
         data_release_version=record["data_package"]["version"],
         dataset_sha256=record["certified_data_artifact"]["sha256"],
         certificate_sha256=certificate_sha256(record),
+        qualification_pair_id=(record.get("certification") or {}).get(
+            "qualification_pair_id"
+        ),
+        model_wheel_sha256=record["model_package"].get("sha256"),
+        core_wheel_sha256=bundle["packages"][CORE_PACKAGE].get("sha256"),
     )
 
 
@@ -559,8 +564,10 @@ def prepare_candidate_commit(
         cwd=repo_root,
     )
     run([python, "scripts/release_lock.py"], cwd=repo_root)
+    # Prepare the candidate's replacement sidecars before strict verification:
+    # the committed sidecars still authenticate the previous data release.
     run(
-        [python, "scripts/bundle.py", "generate", "--include-tros", "--strict-tros"],
+        [python, "scripts/bundle.py", "generate", "--include-tros"],
         cwd=repo_root,
     )
     constants = rewrite_certified_constants(
@@ -827,8 +834,26 @@ def stage_attempt(
     candidate_payload: Mapping[str, Any],
     harness: QualificationHarness,
 ) -> None:
-    write_json(attempt_dir / "candidate.json", dict(candidate_payload))
-    write_json(attempt_dir / "harness.json", harness.canonical_payload())
+    payloads = {
+        attempt_dir / "candidate.json": dict(candidate_payload),
+        attempt_dir / "harness.json": harness.canonical_payload(),
+    }
+    for path, payload in payloads.items():
+        if path.exists() and read_json(path) != payload:
+            raise ValueError(f"A staged attempt's {path.name} is immutable.")
+    staging_path = attempt_dir / "staging.json"
+    if not staging_path.exists():
+        # Persist staging order in the ledger, never infer it from finalization
+        # time, commit hashes or filesystem mtimes. Legacy attempts precede
+        # newly staged attempts and keep their existing receipt bytes.
+        prior_orders = [
+            int(read_json(path)["sequence"])
+            for path in attempt_dir.parent.glob("*/staging.json")
+        ]
+        write_json(staging_path, {"sequence": max(prior_orders, default=0) + 1})
+    for path, payload in payloads.items():
+        if not path.exists():
+            write_json(path, payload)
 
 
 def write_gate_results(
@@ -864,6 +889,15 @@ def finalize_attempt(
 ) -> QualificationReceipt:
     """Assemble and record the receipt for a staged attempt."""
 
+    receipt_path = attempt_dir / "qualification_receipt.json"
+    existing = None
+    if receipt_path.exists():
+        existing = QualificationReceipt.model_validate(read_json(receipt_path))
+        if existing.verdict != "incomplete":
+            # A terminal attempt is immutable, including its completion time.
+            # Retry publication if an earlier run stopped after saving it.
+            _publish_latest_attempt_receipt(attempt_dir, ledger_root, existing)
+            return existing
     candidate = read_json(attempt_dir / "candidate.json")
     pair = CandidatePair.model_validate(candidate["pair"])
     harness = QualificationHarness.model_validate(
@@ -901,11 +935,89 @@ def finalize_attempt(
         previous=previous,
         replay=replay_reference,
     )
-    write_json(attempt_dir / "qualification_receipt.json", receipt.canonical_payload())
+    # Pending receipts may advance to terminal when replay finishes. Preserve
+    # every version under its digest; terminal attempt receipts never change.
+    if existing is not None:
+        snapshot = attempt_dir / "receipts" / f"{existing.receipt_sha256}.json"
+        if not snapshot.exists():
+            write_json(snapshot, existing.canonical_payload())
+    snapshot = attempt_dir / "receipts" / f"{receipt.receipt_sha256}.json"
+    if not snapshot.exists():
+        write_json(snapshot, receipt.canonical_payload())
+    write_json(receipt_path, receipt.canonical_payload())
+    _publish_latest_attempt_receipt(attempt_dir, ledger_root, receipt)
+    return receipt
+
+
+def _publish_latest_attempt_receipt(
+    attempt_dir: Path, ledger_root: Path, receipt: QualificationReceipt
+) -> None:
+    """Publish by staging order, repairing interrupted publication on retry."""
+
+    pair = receipt.pair
     pair_dir = pair_directory(ledger_root, "uk", pair.pair_id)
     write_json(pair_dir / "pair.json", pair.canonical_payload())
-    write_json(pair_dir / "qualification_receipt.json", receipt.canonical_payload())
-    return receipt
+    staging_path = attempt_dir / "staging.json"
+    sequence = int(read_json(staging_path)["sequence"]) if staging_path.exists() else 0
+    latest_path = pair_dir / "qualification_receipt.json"
+    latest_attempt_path = pair_dir / "latest_attempt.json"
+    latest_sequence = -1
+    latest_attempt_key = None
+    latest_pointer = (
+        read_json(latest_attempt_path) if latest_attempt_path.exists() else None
+    )
+    if latest_path.exists():
+        # Receipt identity is authoritative: a crash can leave a stale pointer.
+        # Recover staging order from immutable receipts/snapshots, including
+        # old ledgers and receipts with a receipt-bound acceptance.
+        latest = QualificationReceipt.model_validate(read_json(latest_path))
+        latest_sequence = 0
+        previous_paths = [
+            *pair_dir.glob("attempts/*/qualification_receipt.json"),
+            *pair_dir.glob("attempts/*/receipts/*.json"),
+        ]
+        for previous_path in previous_paths:
+            previous = QualificationReceipt.model_validate(read_json(previous_path))
+            if previous.unreviewed_sha256 != latest.unreviewed_sha256:
+                continue
+            previous_attempt = (
+                previous_path.parent.parent
+                if previous_path.parent.name == "receipts"
+                else previous_path.parent
+            )
+            previous_stage = previous_attempt / "staging.json"
+            previous_sequence = (
+                int(read_json(previous_stage)["sequence"])
+                if previous_stage.exists()
+                else 0
+            )
+            if previous_sequence >= latest_sequence:
+                latest_sequence = previous_sequence
+                latest_attempt_key = previous_attempt.name
+    elif latest_pointer is not None:
+        # Preserve the known order if only the publication pointer survived.
+        latest_sequence = int(latest_pointer["sequence"])
+        latest_attempt_key = latest_pointer["attempt_key"]
+    same_attempt = latest_attempt_key == attempt_dir.name
+    update_pending = (
+        same_attempt
+        and latest_path.exists()
+        and QualificationReceipt.model_validate(read_json(latest_path)).verdict
+        == "incomplete"
+    )
+    if (
+        sequence > latest_sequence
+        or update_pending
+        or (same_attempt and not latest_path.exists())
+    ):
+        write_json(latest_path, receipt.canonical_payload())
+        latest_attempt_key = attempt_dir.name
+        latest_sequence = sequence
+    expected_pointer = {"attempt_key": latest_attempt_key, "sequence": latest_sequence}
+    if latest_attempt_key is not None and latest_pointer != expected_pointer:
+        # Repair only the pointer when the published receipt already belongs
+        # to the latest attempt, preserving any receipt-bound review acceptance.
+        write_json(latest_attempt_path, expected_pointer)
 
 
 def attempt_is_waiting_for_replay(attempt_dir: Path) -> bool:
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index 41086dc4..6717203e 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -19,6 +19,8 @@
 import hashlib
 import json
 import shutil
+import subprocess
+import sys
 from pathlib import Path
 from types import SimpleNamespace
 
@@ -253,6 +255,142 @@ def test_constant_rewrite_leaves_no_old_values(tmp_path):
     assert rewrite_certified_constants(tmp_path, replacements) == []
 
 
+@pytest.mark.parametrize("qualification_only", [False, True])
+def test_preparation_generates_new_sidecars_and_verifies_the_exact_pair(
+    tmp_path, monkeypatch, qualification_only
+):
+    """Run preparation, certification and real TRO generation without a network."""
+
+    from policyengine.provenance import certification, manifest
+    from policyengine.provenance.uk_qualification import prepare_candidate_commit
+
+    monkeypatch.syspath_prepend(str(REPO_ROOT / "scripts"))
+    import bundle as maintenance
+    import certify_data_release as certify_script
+    import generate_bundle_artifacts as artifacts
+    import generate_trace_tros as tros
+
+    release = json.loads(json.dumps(MANIFEST))
+    release["build"].update(
+        built_with_model_package={
+            "name": "policyengine-uk",
+            "version": "2.100.0" if qualification_only else "2.126.8",
+        },
+        built_with_core_package={
+            "name": "policyengine-core",
+            "version": "3.0.0" if qualification_only else "3.33.0",
+        },
+    )
+    release_bytes = json.dumps(release).encode()
+    resolved, _ = _resolver(hf_file=lambda *args: release_bytes)
+    pair = resolved.pair
+    bundle_dir = tmp_path / "src/policyengine/data/bundle"
+    bundle_dir.mkdir(parents=True)
+    source = json.loads(json.dumps(BUNDLE))
+    source["data_releases"].pop("us")
+    source["packages"].pop("policyengine-us")
+    for packages in source["extras"].values():
+        if "policyengine-us" in packages:
+            packages.remove("policyengine-us")
+    bundle_path = bundle_dir / "manifest.json"
+    write_json(bundle_path, source)
+    sidecar = bundle_dir / "uk.trace.tro.jsonld"
+    old_sidecar = (
+        REPO_ROOT / "src/policyengine/data/bundle/uk.trace.tro.jsonld"
+    ).read_bytes()
+    sidecar.write_bytes(old_sidecar)
+    shutil.copy(REPO_ROOT / "pyproject.toml", tmp_path / "pyproject.toml")
+    (tmp_path / "changelog.d").mkdir()
+    for name in ("test_models.py", "test_release_manifests.py", "test_uk_regions.py"):
+        (tmp_path / "tests").mkdir(exist_ok=True)
+        shutil.copy(REPO_ROOT / "tests" / name, tmp_path / "tests" / name)
+
+    def country_manifest(country):
+        assert country == "uk"
+        result = manifest.CountryReleaseManifest.model_validate(
+            json.loads(bundle_path.read_text())["data_releases"][country]
+        )
+        result.source_sha256 = hashlib.sha256(bundle_path.read_bytes()).hexdigest()
+        return result
+
+    def data_manifest(country=None):
+        result = manifest.DataReleaseManifest.model_validate_json(release_bytes)
+        result.source_sha256 = hashlib.sha256(release_bytes).hexdigest()
+        return result
+
+    monkeypatch.setattr(certify_script, "REPO_ROOT", tmp_path)
+    monkeypatch.setattr(maintenance, "REPO_ROOT", tmp_path)
+    monkeypatch.setattr(artifacts, "REPO_ROOT", tmp_path)
+    monkeypatch.setattr(artifacts, "BUNDLE_MANIFEST", bundle_path)
+    monkeypatch.setattr(artifacts, "PYPROJECT", tmp_path / "pyproject.toml")
+    load_bundle = artifacts.load_bundle_manifest
+    monkeypatch.setattr(
+        artifacts, "load_bundle_manifest", lambda path=bundle_path: load_bundle(path)
+    )
+    monkeypatch.setattr(tros, "BUNDLE_MANIFEST", bundle_path)
+    monkeypatch.setattr(tros, "BUNDLE_TRO_DIR", bundle_dir)
+    monkeypatch.setattr(tros, "BUNDLE_LOCK", tmp_path / "uv.lock")
+    monkeypatch.setattr(tros, "get_release_manifest", country_manifest)
+    monkeypatch.setattr(tros, "get_data_release_manifest", data_manifest)
+    monkeypatch.setattr(
+        certification,
+        "fetch_release_manifest",
+        lambda uri, **kw: (
+            data_manifest(),
+            pair.data.release_manifest_sha256,
+            certification.parse_manifest_uri(uri),
+        ),
+    )
+    monkeypatch.setattr(
+        certification,
+        "fetch_pypi_wheel_metadata",
+        lambda *args: {
+            "sha256": pair.model.wheel_sha256,
+            "url": resolved.model_wheel.url,
+        },
+    )
+    monkeypatch.setattr(certification, "head_artifact", lambda *args, **kw: True)
+    monkeypatch.setattr(
+        certification, "required_supplemental_release_files", lambda *args: []
+    )
+    calls = []
+
+    def run(command, *, cwd, env=None):
+        calls.append(command)
+        assert cwd == tmp_path
+        if command[1] == "scripts/bundle.py":
+            assert maintenance.main(command[2:]) == 0
+        elif command[:2] == ["uv", "lock"]:
+            (tmp_path / "uv.lock").write_text(
+                "[[package]]\n"
+                'name = "policyengine-uk"\n'
+                f'version = "{pair.model.version}"\n'
+                'source = { registry = "https://pypi.org/simple" }\n'
+                f'wheels = [{{url = "{resolved.model_wheel.url}", hash = "sha256:{pair.model.wheel_sha256}"}}]\n'
+            )
+        else:
+            assert command[1] == "scripts/release_lock.py"
+        return subprocess.CompletedProcess(command, 0)
+
+    prepared = prepare_candidate_commit(
+        tmp_path, resolved, python=sys.executable, run=run, refresh_snapshots=False
+    )
+    assert sidecar.read_bytes() != old_sidecar
+    assert pair.data.release_manifest_sha256.encode() in sidecar.read_bytes()
+    assert prepared["compatibility_basis"] == (
+        "qualified_exact_pair" if qualification_only else "built_with_model_package"
+    )
+    assert (tmp_path / prepared["changelog_fragment"]).is_file()
+    assert maintenance.main(["check", "--include-tros", "--strict-tros"]) == 0
+    assert calls[-1][2:] == ["check", "--include-tros", "--strict-tros"]
+    if qualification_only:
+        changed = json.loads(bundle_path.read_bytes())
+        changed["packages"]["policyengine-core"]["version"] = "99.0.0"
+        write_json(bundle_path, changed)
+        with pytest.raises(ValueError, match="runtime core.*qualified exact pair"):
+            tros.generated_tros(strict=True)
+
+
 def test_replay_request_is_valid_for_the_scorecard():
     pair = make_pair()
     release_bundle = dict(
@@ -559,6 +697,189 @@ def test_attempt_lifecycle(tmp_path):
     )
     assert final.verdict == "qualified"
     assert final.replay.request_id == request.request_id
+    assert (attempt / "receipts" / f"{receipt.receipt_sha256}.json").is_file()
+    assert (attempt / "receipts" / f"{final.receipt_sha256}.json").is_file()
+    assert (
+        read_json(attempt / "receipts" / f"{receipt.receipt_sha256}.json")
+        == receipt.canonical_payload()
+    )
+
+
+def test_older_attempt_finalization_preserves_latest_staged_attempt(tmp_path):
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    pair = make_pair()
+    # The staging order deliberately differs from directory/commit order.
+    older = attempt_directory(tmp_path, "uk", pair.pair_id, "ffffffffffff")
+    newer = attempt_directory(tmp_path, "uk", pair.pair_id, "aaaaaaaaaaaa")
+    payload = {"pair": pair.canonical_payload(), "previous_certificate": None}
+    stage_attempt(older, payload, HARNESS)
+    newer_harness = HARNESS.model_copy(update={"git_commit": "a" * 40})
+    stage_attempt(newer, payload, newer_harness)
+    for attempt in (older, newer):
+        write_gate_results(attempt, gates(), {})
+    newest = finalize_attempt(
+        newer, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T10:00:00Z"
+    )
+    old = finalize_attempt(
+        older, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    latest = read_json(tmp_path / "uk" / pair.pair_id / "qualification_receipt.json")
+    assert latest == newest.canonical_payload()
+    assert read_json(older / "qualification_receipt.json") == old.canonical_payload()
+    assert read_json(newer / "qualification_receipt.json") == newest.canonical_payload()
+
+
+def test_terminal_attempt_receipt_is_immutable_and_finalization_is_idempotent(tmp_path):
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import (
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    pair = make_pair()
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, "abcdef123456")
+    stage_attempt(attempt, {"pair": pair.canonical_payload()}, HARNESS)
+    write_gate_results(attempt, gates(), {})
+    original = finalize_attempt(
+        attempt, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T10:00:00Z"
+    )
+    original_bytes = (attempt / "qualification_receipt.json").read_bytes()
+    write_gate_results(attempt, gates(replay="fail"), {})
+    repeated = finalize_attempt(
+        attempt, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    assert repeated == original
+    assert (attempt / "qualification_receipt.json").read_bytes() == original_bytes
+
+
+def test_new_staged_attempt_advances_a_legacy_latest_receipt(tmp_path):
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    legacy = make_receipt()
+    latest_path = tmp_path / "uk" / legacy.pair_id / "qualification_receipt.json"
+    write_json(latest_path, legacy.canonical_payload())
+    attempt = attempt_directory(tmp_path, "uk", legacy.pair_id, "new-attempt")
+    stage_attempt(attempt, {"pair": legacy.pair.canonical_payload()}, HARNESS)
+    write_gate_results(attempt, gates(), {})
+    current = finalize_attempt(
+        attempt, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    assert read_json(latest_path) == current.canonical_payload()
+
+
+@pytest.mark.parametrize(
+    "interrupted", ["missing", "older", "missing-pointer", "missing-receipt"]
+)
+def test_terminal_finalization_repairs_interrupted_latest_publication(
+    tmp_path, interrupted
+):
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    pair = make_pair()
+    payload = {"pair": pair.canonical_payload()}
+    older = attempt_directory(tmp_path, "uk", pair.pair_id, "older")
+    stage_attempt(older, payload, HARNESS)
+    write_gate_results(older, gates(), {})
+    old_receipt = finalize_attempt(
+        older, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T09:00:00Z"
+    )
+    current = attempt_directory(tmp_path, "uk", pair.pair_id, "newer")
+    stage_attempt(current, payload, HARNESS.model_copy(update={"git_commit": "a" * 40}))
+    write_gate_results(current, gates(), {})
+    receipt = finalize_attempt(
+        current, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T10:00:00Z"
+    )
+    original_bytes = (current / "qualification_receipt.json").read_bytes()
+    pair_dir = tmp_path / "uk" / pair.pair_id
+    latest = pair_dir / "qualification_receipt.json"
+    pointer = pair_dir / "latest_attempt.json"
+    if interrupted == "older":
+        write_json(latest, old_receipt.canonical_payload())
+        write_json(pointer, {"attempt_key": "older", "sequence": 1})
+    else:
+        if interrupted != "missing-pointer":
+            latest.unlink()
+        if interrupted != "missing-receipt":
+            pointer.unlink()
+    repeated = finalize_attempt(
+        current, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    assert repeated == receipt
+    assert (current / "qualification_receipt.json").read_bytes() == original_bytes
+    assert read_json(latest) == receipt.canonical_payload()
+    assert read_json(pointer) == {"attempt_key": "newer", "sequence": 2}
+    finalize_attempt(
+        older, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T12:00:00Z"
+    )
+    assert read_json(latest) == receipt.canonical_payload()
+
+
+def test_stale_latest_pointer_cannot_replace_a_newer_incomplete_receipt(tmp_path):
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        finalize_attempt,
+        stage_attempt,
+        write_gate_results,
+    )
+
+    pair = make_pair()
+    payload = {"pair": pair.canonical_payload()}
+    older = attempt_directory(tmp_path, "uk", pair.pair_id, "older")
+    stage_attempt(older, payload, HARNESS)
+    write_gate_results(older, gates(), {})
+    finalize_attempt(
+        older, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T09:00:00Z"
+    )
+    newer = attempt_directory(tmp_path, "uk", pair.pair_id, "newer")
+    stage_attempt(newer, payload, HARNESS.model_copy(update={"git_commit": "a" * 40}))
+    write_gate_results(newer, gates(replay="unavailable"), {})
+    current = finalize_attempt(
+        newer, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T10:00:00Z"
+    )
+    pair_dir = tmp_path / "uk" / pair.pair_id
+    write_json(
+        pair_dir / "latest_attempt.json", {"attempt_key": "older", "sequence": 1}
+    )
+    finalize_attempt(
+        older, tmp_path, issued_by=ISSUED, completed_at="2026-10-15T11:00:00Z"
+    )
+    assert (
+        read_json(pair_dir / "qualification_receipt.json")
+        == current.canonical_payload()
+    )
+    assert read_json(pair_dir / "latest_attempt.json") == {
+        "attempt_key": "newer",
+        "sequence": 2,
+    }
 
 
 # --- Release dispatch ----------------------------------------------------------------

From b87a77649e873c28d9944ff240ccfeec5681c531 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:29:44 -0400
Subject: [PATCH 21/45] Require full contract coverage and bind finalized gate
 evidence to the tested pair

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py | 272 ++++++++++++++--
 tests/test_uk_candidate_gates.py            | 331 +++++++++++++++++++-
 2 files changed, 570 insertions(+), 33 deletions(-)

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index a8bdc845..4d03d799 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -16,10 +16,13 @@
 
 import hashlib
 import importlib
+import inspect
 import io
 import json
 import math
+import re
 import traceback
+from collections import Counter
 from collections.abc import Callable, Iterable, Mapping, Sequence
 from importlib import metadata as importlib_metadata
 from pathlib import Path
@@ -34,6 +37,7 @@
     CandidatePair,
     GateResult,
     QualificationHarness,
+    QualificationReceipt,
 )
 from policyengine.provenance.receipt import content_sha256
 from policyengine.provenance.wheels import (
@@ -621,13 +625,13 @@ def _load_entrypoint(
     return function, module
 
 
-def _contract_coverage(module: Any) -> Optional[dict[str, list[Any]]]:
+def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
     """What a full contract run covers, as the runner's own module declares it.
 
     ``ROUTES`` (route ids), ``CASES`` (objects with an ``id`` and optional
-    ``routes`` limiting where the case runs) and ``PROPERTIES`` (keyed by
-    property id). ``None`` when the module does not declare them, so coverage
-    cannot be checked.
+    ``routes`` limiting where the case runs and ``checks`` describing each
+    expected value), ``UNSUPPORTED_ROUTES`` and ``PROPERTIES`` (keyed by
+    property id). ``None`` when the module does not declare the essentials.
     """
 
     try:
@@ -639,15 +643,67 @@ def _contract_coverage(module: Any) -> Optional[dict[str, list[Any]]]:
                 case.routes if getattr(case, "routes", None) is not None else routes
             )
         ]
+        checks: list[tuple[str, str, Optional[str]]] = []
+        pending: dict[tuple[str, str, Optional[str]], str] = {}
+        unsupported = getattr(module, "UNSUPPORTED_ROUTES", {})
+        for case in module.CASES:
+            for route in (
+                case.routes if getattr(case, "routes", None) is not None else routes
+            ):
+                if route in unsupported:
+                    checks.append((str(case.id), str(route), None))
+                elif getattr(case, "expect_error", None) is not None:
+                    checks.append((str(case.id), str(route), "rejected"))
+                else:
+                    # W1 declares expected values in Case.checks. Additional
+                    # isolation/state rows are generated by runtime behavior,
+                    # without a declarative coverage matrix, so require every
+                    # declared value rather than inventing those extra rows.
+                    for check in getattr(case, "checks", ()):
+                        key = (
+                            str(case.id),
+                            str(route),
+                            f"{check.target}:{check.name}:{check.year}",
+                        )
+                        checks.append(key)
+                        if getattr(check, "pending", None) is not None:
+                            pending[key] = str(check.pending)
         return {
             "routes": routes,
             "pairs": pairs,
             "properties": [str(name) for name in module.PROPERTIES],
+            "checks": checks,
+            "pending_checks": pending,
+            "pending_decisions": {
+                str(decision) for decision in getattr(module, "PENDING_DECISIONS", ())
+            },
+            "unsupported_routes": unsupported,
+            "population": getattr(module, "POPULATION_CHECKS", None),
         }
     except AttributeError:
         return None
 
 
+def _declared_population_checks(
+    module_name: str, importer: Callable[[str], Any]
+) -> list[str]:
+    """Population check IDs documented by W1's population runner itself.
+
+    W1 currently exposes no machine-readable per-route population coverage
+    matrix. Its module docstring declares the checks by ID, which supports
+    requiring every declared check, but not inventing route counts. Prefer
+    an explicit declaration if the runner adds one.
+    """
+
+    module = importer(module_name.rsplit(".", 1)[0] + ".budget_reform_population")
+    declared = getattr(module, "POPULATION_CHECKS", None)
+    if declared is not None:
+        return [str(check) for check in declared]
+    return re.findall(
+        r"^``([a-z][a-z0-9_]+)``$", inspect.getdoc(module) or "", re.MULTILINE
+    )
+
+
 #: Report sections: the key that names each row, and what a row is called.
 _CONTRACT_SECTIONS = (
     ("cases", "case_id", "case"),
@@ -665,6 +721,7 @@ def reform_contract(
     max_examples: int,
     expected_versions: Optional[Mapping[str, str]] = None,
     expected_dataset_sha256: Optional[str] = None,
+    pending_decisions: Sequence[str] = (),
     importer: Callable[[str], Any] = importlib.import_module,
 ) -> GateOutcome:
     """Run the Budget reform contract (W1) on every route and gate on its report.
@@ -672,11 +729,11 @@ def reform_contract(
     ``fail`` when any case, sampled property or population check fails or
     errors. ``error`` when the report cannot be trusted as a full run of this
     candidate:
-    - it does not cover every route, every case on each of its routes and
-      every sampled property the runner's module declares (``ROUTES``,
-      ``CASES``, ``PROPERTIES``), or a property passed on fewer examples than
-      requested;
-    - a pending row lacks its ``decision_id``, or an unsupported case or
+    - it does not cover every declared case check on each route, every
+      declared population check and every sampled property, or a property
+      passed on fewer examples than requested;
+    - a property is pending, a pending row names no authorized decision,
+      or an unsupported case or
       population check lacks its ``reason``;
     - a sampled property did not run;
     - population checks are missing although a dataset was given;
@@ -721,6 +778,10 @@ def reform_contract(
     pending: list[str] = []
     unsupported: list[str] = []
     counts = dict.fromkeys(_CONTRACT_STATUSES, 0)
+    coverage = _contract_coverage(runner_module)
+    allowed_pending = set(pending_decisions) | (
+        coverage["pending_decisions"] if coverage else set()
+    )
     for section, key, noun in _CONTRACT_SECTIONS:
         for row in report.get(section) or []:
             status = row.get("status")
@@ -732,8 +793,28 @@ def reform_contract(
             if status in ("fail", "error"):
                 failures.append(label)
             elif status == "pending":
-                if not row.get("decision_id"):
+                decision = row.get("decision_id")
+                declared_decision = (
+                    coverage["pending_checks"].get(
+                        (
+                            str(row.get("case_id")),
+                            str(row.get("route")),
+                            row.get("check"),
+                        )
+                    )
+                    if coverage and section == "cases"
+                    else None
+                )
+                if section == "properties":
+                    malformed.append(
+                        f"{label} did not run: properties cannot be pending"
+                    )
+                elif not decision:
                     malformed.append(f"{label} is pending without a decision_id")
+                elif decision != declared_decision and decision not in allowed_pending:
+                    malformed.append(
+                        f"{label} is pending for undeclared decision {decision}"
+                    )
                 pending.append(label)
             elif status == "unsupported":
                 if section == "properties":
@@ -750,7 +831,6 @@ def reform_contract(
     # A full run covers what the runner itself declares: every route, every
     # case on each route it runs on, and every sampled property with the
     # examples asked for. A report that drops any of it does not qualify.
-    coverage = _contract_coverage(runner_module)
     if coverage is None:
         malformed.append(
             "the runner declares no ROUTES, CASES and PROPERTIES, so the "
@@ -777,6 +857,67 @@ def reform_contract(
                 f"{len(absent)} case-route pair(s) have no row: "
                 + ", ".join(absent[:4])
             )
+        reported_checks = Counter(
+            (str(row.get("case_id")), str(row.get("route")), row.get("check"))
+            for row in report.get("cases") or []
+        )
+        # W1 replaces a case-route's checks with a single error row when
+        # constructing its simulation crashes. That is a complete attempted
+        # run and already fails the gate; it cannot exempt a passing report.
+        crashed = {
+            (str(row.get("case_id")), str(row.get("route")))
+            for row in report.get("cases") or []
+            if row.get("status") == "error"
+            and row.get("check") is None
+            and row.get("detail")
+        }
+        absent_checks = (
+            Counter(key for key in coverage["checks"] if key[:2] not in crashed)
+            - reported_checks
+        )
+        if absent_checks:
+            malformed.append(
+                f"{sum(absent_checks.values())} declared case check(s) have no row: "
+                + ", ".join(
+                    f"{case}@{route}:{check}"
+                    for case, route, check in list(absent_checks)[:4]
+                )
+            )
+        for row in report.get("cases") or []:
+            if row.get("route") in coverage["unsupported_routes"] and (
+                row.get("check") is not None or row.get("status") != "unsupported"
+            ):
+                malformed.append(
+                    f"case {row.get('case_id')}@{row.get('route')} is not the declared unsupported route row"
+                )
+        if dataset_path is not None:
+            declared_population = coverage["population"]
+            if declared_population is None:
+                try:
+                    module_name = (
+                        entrypoint.partition(":")[0]
+                        if ":" in entrypoint
+                        else entrypoint.rpartition(".")[0]
+                    )
+                    declared_population = _declared_population_checks(
+                        module_name, importer
+                    )
+                except (ImportError, AttributeError):
+                    declared_population = []
+            if not declared_population:
+                malformed.append(
+                    "the runner declares no population checks, so population coverage cannot be checked"
+                )
+            else:
+                population = {
+                    str(row.get("check_id")) for row in report.get("population") or []
+                }
+                absent_population = sorted(set(declared_population) - population)
+                if absent_population:
+                    malformed.append(
+                        "declared population check(s) have no row: "
+                        + ", ".join(absent_population)
+                    )
         properties = {
             str(row.get("property_id")): row for row in report.get("properties") or []
         }
@@ -1603,6 +1744,10 @@ def run_gates(
         result, item = run_gate(gate_id, function)
         if result.gate_id != gate_id:
             result = result.model_copy(update={"gate_id": gate_id})
+        # Orchestration may append source/tool metadata to a gate's evidence.
+        # Bind the result to the complete JSON that will actually be stored.
+        item = _json_safe(item)
+        result = result.model_copy(update={"evidence_sha256": evidence_sha256(item)})
         results.append(result)
         evidence[gate_id] = item
     return results, evidence
@@ -1621,33 +1766,101 @@ def _download(url: str, destination: Path, *, get: Callable[..., Any]) -> Path:
 def _previous_gate_evidence(
     ledger_root: Optional[Path], previous: Optional[Mapping[str, Any]]
 ) -> dict[str, Any]:
-    """Evidence the previous certificate's qualification recorded, if any."""
+    """Verified evidence of the exact certified pair and receipt's attempt.
+
+    Legacy certificates that cannot bind every wheel and data pin by pair ID,
+    or incomplete/corrupt evidence, fall back to recomputation by the caller.
+    """
 
     if ledger_root is None or not previous:
         return {}
-    base = ledger_root / "uk"
-    if not base.is_dir():
+    pair_id = previous.get("qualification_pair_id")
+    if not isinstance(pair_id, str) or not re.fullmatch(r"[a-f0-9]{64}", pair_id):
         return {}
-    for receipt_path in base.glob("*/qualification_receipt.json"):
-        receipt = json.loads(receipt_path.read_text())
-        pair = receipt.get("pair", {})
-        if (
-            pair.get("model", {}).get("version") == previous.get("model_version")
-            and pair.get("data", {}).get("release_version")
-            == previous.get("data_release_version")
-            and receipt.get("verdict") in ("qualified", "needs_review")
+    receipt_path = ledger_root / "uk" / pair_id / "qualification_receipt.json"
+    try:
+        receipt = QualificationReceipt.model_validate_json(receipt_path.read_text())
+        pair = receipt.pair
+        if not receipt.promotable or receipt.pair_id != pair_id:
+            return {}
+        expected = (
+            (pair.model.version, previous.get("model_version")),
+            (pair.core.version, previous.get("core_version")),
+            (pair.data.release_version, previous.get("data_release_version")),
+            (pair.data.dataset_sha256, previous.get("dataset_sha256")),
+        )
+        if any(actual != certified for actual, certified in expected):
+            return {}
+        # The pair ID binds all wheels and data pins even for certificates
+        # whose bundle's package record does not repeat the core wheel hash.
+        for field, actual in (
+            ("model_wheel_sha256", pair.model.wheel_sha256),
+            ("core_wheel_sha256", pair.core.wheel_sha256),
+        ):
+            if previous.get(field) is not None and previous[field] != actual:
+                return {}
+        for attempt_receipt in sorted(
+            (receipt_path.parent / "attempts").glob("*/qualification_receipt.json")
         ):
+            attempt = QualificationReceipt.model_validate_json(
+                attempt_receipt.read_text()
+            )
+            # Review acceptance can change the latest receipt without changing
+            # the immutable attempt's underlying qualification.
+            if attempt.unreviewed_sha256 != receipt.unreviewed_sha256:
+                continue
+            harness = json.loads((attempt_receipt.parent / "harness.json").read_text())
+            if harness != receipt.harness.canonical_payload():
+                continue
+            by_gate = {gate.gate_id: gate for gate in receipt.gates}
             found: dict[str, Any] = {}
-            attempts = sorted((receipt_path.parent / "attempts").glob("*/gates"))
-            if attempts:
-                for name in ("supported_years", "budget_inputs"):
-                    path = attempts[-1] / f"{name}.json"
-                    if path.exists():
-                        found[name] = json.loads(path.read_text())
-            return found
+            for name in ("supported_years", "budget_inputs"):
+                gate = by_gate.get(name)
+                evidence = json.loads(
+                    (attempt_receipt.parent / "gates" / f"{name}.json").read_text()
+                )
+                if (
+                    not gate
+                    or gate.status not in ("pass", "needs_review")
+                    or gate.evidence_sha256 != evidence_sha256(evidence)
+                ):
+                    return {}
+                found[name] = evidence
+            if _valid_previous_snapshot_evidence(found):
+                return found
+            return {}
+    except (OSError, ValueError, TypeError, AttributeError):
+        # An unavailable cache is not qualification evidence; recompute it.
+        return {}
     return {}
 
 
+def _valid_previous_snapshot_evidence(evidence: Mapping[str, Any]) -> bool:
+    years = evidence["supported_years"].get("supported_years")
+    inputs = evidence["budget_inputs"]
+    missing = inputs.get("missing_inputs")
+    unusable = inputs.get("unusable_critical")
+    return (
+        isinstance(years, list)
+        and bool(years)
+        and all(
+            isinstance(year, int) and not isinstance(year, bool) and year > 0
+            for year in years
+        )
+        and len(years) == len(set(years))
+        and isinstance(missing, list)
+        and all(isinstance(name, str) and bool(name) for name in missing)
+        and len(missing) == len(set(missing))
+        and isinstance(unusable, list)
+        and all(
+            isinstance(row, list)
+            and len(row) == 2
+            and all(isinstance(value, str) and bool(value) for value in row)
+            for row in unusable
+        )
+    )
+
+
 def run_candidate_gates(
     resolved: Any,
     harness: QualificationHarness,
@@ -1799,6 +2012,7 @@ def gate_contract() -> GateOutcome:
                 pair.core.name: pair.core.version,
             },
             expected_dataset_sha256=pair.data.dataset_sha256,
+            pending_decisions=settings.get("pending_decisions", ()),
         )
 
     def metrics_tool() -> Path:
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 5ca25c7e..17e057c9 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -19,6 +19,7 @@
 import hashlib
 import io
 import json
+import sys
 import zipfile
 from pathlib import Path
 from types import SimpleNamespace
@@ -48,7 +49,7 @@
     record_digest_to_hex,
     verify_installed_against_wheel,
 )
-from tests.qualification_fixtures import HARNESS, make_pair
+from tests.qualification_fixtures import HARNESS, make_pair, make_receipt
 
 # --- Installed versions --------------------------------------------------------
 
@@ -549,16 +550,61 @@ def _declared_coverage(source):
     source = source or {}
     by_case = {}
     for row in source.get("cases") or []:
-        by_case.setdefault(row.get("case_id"), []).append(row.get("route"))
+        by_case.setdefault(row.get("case_id"), []).append(row)
     return {
         "ROUTES": tuple(source.get("routes") or ()),
         "CASES": tuple(
-            SimpleNamespace(id=case, routes=tuple(dict.fromkeys(routes)))
-            for case, routes in by_case.items()
+            SimpleNamespace(
+                id=case,
+                routes=tuple(dict.fromkeys(row.get("route") for row in rows)),
+                checks=tuple(
+                    SimpleNamespace(
+                        target=label.split(":")[0],
+                        name=label.split(":")[1],
+                        year=int(label.split(":")[2]),
+                        pending=next(
+                            (
+                                row.get("decision_id")
+                                for row in rows
+                                if row.get("check") == label
+                            ),
+                            None,
+                        ),
+                    )
+                    for label in dict.fromkeys(row.get("check") for row in rows)
+                    if label
+                    and len(label.split(":")) == 3
+                    and label.split(":")[0]
+                    not in ("baseline_isolation", "unreformed_after_reform")
+                ),
+                expect_error="rejected"
+                if any(row.get("check") == "rejected" for row in rows)
+                else None,
+            )
+            for case, rows in by_case.items()
         ),
         "PROPERTIES": {
             row.get("property_id"): "" for row in source.get("properties") or []
         },
+        "UNSUPPORTED_ROUTES": {
+            row["route"]: row.get("reason", "")
+            for row in source.get("cases") or []
+            if row.get("status") == "unsupported"
+            and row.get("check") is None
+            and all(
+                other.get("status") == "unsupported" and other.get("check") is None
+                for other in source.get("cases") or []
+                if other.get("route") == row["route"]
+            )
+        },
+        "PENDING_DECISIONS": {
+            row["decision_id"]
+            for row in source.get("cases") or []
+            if row.get("decision_id")
+        },
+        "POPULATION_CHECKS": tuple(
+            dict.fromkeys(row["check_id"] for row in source.get("population") or [])
+        ),
     }
 
 
@@ -787,6 +833,20 @@ def _drop(report, **sections):
 
 
 COVERAGE_GAPS = {
+    "each case reduced to one check per route": lambda r: _drop(
+        r,
+        cases=list(
+            {(row["case_id"], row["route"]): row for row in r["cases"]}.values()
+        ),
+    ),
+    "all but one population check": lambda r: _drop(r, population=r["population"][:1]),
+    "pending properties with invented decisions": lambda r: _drop(
+        r,
+        properties=[
+            {**row, "status": "pending", "decision_id": "invented", "examples_run": 0}
+            for row in r["properties"]
+        ],
+    ),
     "one case on one route": lambda r: (
         _drop(r, cases=r["cases"][:1], population=r["population"][:1], properties=[])
         | {"routes": r["routes"][:1]}
@@ -842,7 +902,42 @@ def test_a_runner_that_declares_no_coverage_cannot_qualify():
     assert "declares no ROUTES, CASES and PROPERTIES" in result.summary
 
 
+def test_population_coverage_uses_the_population_runners_declarations():
+    """A check added by the runner must be required without a gate-side list."""
+
+    report = _passing_report()
+    importer = _importer(report=report, coverage=report)
+    module = importer("contract")
+    del module.POPULATION_CHECKS
+    population = SimpleNamespace()
+    population.__doc__ = (
+        "Checks:\n\n``new_population_check``\n    Declared by the population runner."
+    )
+    result = reform_contract(
+        entrypoint=ENTRY,
+        dataset_path=Path("dataset.h5"),
+        seed=0,
+        max_examples=20,
+        importer=lambda name: (
+            population if name.endswith("budget_reform_population") else module
+        ),
+    )[0]
+    assert result.status == "error"
+    assert "new_population_check" in result.summary
+
+
 REPORT_TAMPERING = {
+    "invented pending decision": lambda r: _recount(
+        {
+            **r,
+            "cases": [
+                {**row, "decision_id": "invented"}
+                if row["status"] == "pending"
+                else row
+                for row in r["cases"]
+            ],
+        }
+    ),
     "other model": lambda r: r["versions"].update({"policyengine-uk": "2.125.1"}),
     "other core": lambda r: r["versions"].update({"policyengine-core": "3.30.0"}),
     "other dataset": lambda r: r["dataset"].update(sha256="0" * 64),
@@ -1197,6 +1292,234 @@ def function():
 # --- Previous-pair runners -----------------------------------------------------------
 
 
+def _write_previous_receipt(root, pair, evidence, *, attempt="a"):
+    from policyengine.provenance.qualification_ledger import write_json
+
+    receipt = make_receipt(pair)
+    receipt = receipt.model_copy(
+        update={
+            "gates": [
+                gate.model_copy(
+                    update={
+                        "evidence_sha256": gates_module.evidence_sha256(
+                            evidence[gate.gate_id]
+                        )
+                    }
+                )
+                if gate.gate_id in evidence
+                else gate
+                for gate in receipt.gates
+            ]
+        }
+    )
+    pair_dir = root / "uk" / pair.pair_id
+    write_json(pair_dir / "qualification_receipt.json", receipt.canonical_payload())
+    attempt_dir = pair_dir / "attempts" / attempt
+    write_json(attempt_dir / "qualification_receipt.json", receipt.canonical_payload())
+    write_json(attempt_dir / "harness.json", receipt.harness.canonical_payload())
+    for gate_id, value in evidence.items():
+        write_json(attempt_dir / "gates" / f"{gate_id}.json", value)
+    return receipt, attempt_dir
+
+
+def _previous_identity(pair):
+    return {
+        "bundle_version": HARNESS.policyengine_version,
+        "model_version": pair.model.version,
+        "core_version": pair.core.version,
+        "data_release_version": pair.data.release_version,
+        "dataset_sha256": pair.data.dataset_sha256,
+        "qualification_pair_id": pair.pair_id,
+        "model_wheel_sha256": pair.model.wheel_sha256,
+        "core_wheel_sha256": pair.core.wheel_sha256,
+    }
+
+
+def test_previous_evidence_matches_the_exact_certified_core_and_wheels(tmp_path):
+    wrong = make_pair(core="3.32.0")
+    certified = make_pair(core="3.33.0")
+    wrong_evidence = {
+        "supported_years": {"supported_years": [2025]},
+        "budget_inputs": {"missing_inputs": ["age"], "unusable_critical": []},
+    }
+    expected = {
+        "supported_years": {"supported_years": [2025, 2026]},
+        "budget_inputs": {"missing_inputs": [], "unusable_critical": []},
+    }
+    _write_previous_receipt(tmp_path, wrong, wrong_evidence)
+    _write_previous_receipt(tmp_path, certified, expected)
+    assert (
+        gates_module._previous_gate_evidence(tmp_path, _previous_identity(certified))
+        == expected
+    )
+    for wheel in ("core_wheel_sha256", "model_wheel_sha256"):
+        altered = {**_previous_identity(certified), wheel: "0" * 64}
+        assert gates_module._previous_gate_evidence(tmp_path, altered) == {}
+
+
+def test_previous_evidence_belongs_to_the_receipts_attempt(tmp_path):
+    from policyengine.provenance.qualification_ledger import write_json
+
+    pair = make_pair()
+    expected = {
+        "supported_years": {"supported_years": [2025, 2026]},
+        "budget_inputs": {"missing_inputs": [], "unusable_critical": []},
+    }
+    receipt, attempt = _write_previous_receipt(tmp_path, pair, expected)
+    unrelated = attempt.parent / "z"
+    other_receipt = receipt.model_copy(
+        update={"harness": HARNESS.model_copy(update={"git_commit": "1" * 40})}
+    )
+    write_json(
+        unrelated / "qualification_receipt.json", other_receipt.canonical_payload()
+    )
+    for name in expected:
+        write_json(unrelated / "gates" / f"{name}.json", {"untrusted": True})
+    assert (
+        gates_module._previous_gate_evidence(tmp_path, _previous_identity(pair))
+        == expected
+    )
+
+
+@pytest.mark.parametrize(
+    "corruption", ["digest", "shape", "receipt", "missing identity"]
+)
+def test_unverified_previous_evidence_is_recomputed(tmp_path, corruption):
+    from policyengine.provenance.qualification_ledger import write_json
+
+    pair = make_pair()
+    expected = {
+        "supported_years": {"supported_years": [2025, 2026]},
+        "budget_inputs": {"missing_inputs": [], "unusable_critical": []},
+    }
+    receipt, attempt = _write_previous_receipt(tmp_path, pair, expected)
+    previous = _previous_identity(pair)
+    if corruption == "digest":
+        write_json(
+            attempt / "gates" / "supported_years.json", {"supported_years": [2025]}
+        )
+    elif corruption == "shape":
+        invalid = {**expected, "supported_years": {"supported_years": [True]}}
+        _write_previous_receipt(tmp_path, pair, invalid)
+    elif corruption == "receipt":
+        payload = receipt.canonical_payload() | {"verdict": "needs_review"}
+        write_json(attempt.parent.parent / "qualification_receipt.json", payload)
+    else:
+        previous.pop("qualification_pair_id")
+        previous.pop("core_wheel_sha256")
+    assert gates_module._previous_gate_evidence(tmp_path, previous) == {}
+
+
+@pytest.mark.parametrize("corrupt_baseline", [False, True])
+def test_orchestration_hashes_every_finalized_gate_evidence(
+    tmp_path, monkeypatch, corrupt_baseline
+):
+    from policyengine.provenance import dataset_materialization
+    from policyengine.provenance.qualification_ledger import write_json
+
+    pair = make_pair()
+    config = json.loads(
+        (
+            Path(__file__).parents[1] / "src/policyengine/data/qualification/uk.json"
+        ).read_text()
+    )
+    monkeypatch.setattr(
+        dataset_materialization,
+        "materialize_dataset",
+        lambda *a, **k: SimpleNamespace(path=tmp_path / "dataset.h5"),
+    )
+    monkeypatch.setitem(
+        sys.modules,
+        "policyengine_uk.system",
+        SimpleNamespace(system=SimpleNamespace(variables={})),
+    )
+    baseline = {
+        "budget_inputs": {"missing_inputs": [], "unusable_critical": []},
+        "supported_years": {"supported_years": [2025]},
+    }
+    _, attempt = _write_previous_receipt(tmp_path, pair, baseline)
+    if corrupt_baseline:
+        write_json(
+            attempt / "gates" / "supported_years.json", {"supported_years": [2024]}
+        )
+    snapshots = []
+
+    def snapshot(*args, **kwargs):
+        snapshots.append(args[0])
+        return {
+            "missing_inputs": [],
+            "unusable_critical": [],
+            "supported_years": [2025],
+        }
+
+    monkeypatch.setattr(gates_module, "run_inputs_snapshot", snapshot)
+    monkeypatch.setattr(gates_module, "vendor_metrics_tool", lambda *a, **k: tmp_path)
+    monkeypatch.setattr(gates_module, "load_standard_reforms", lambda *a: [])
+    monkeypatch.setattr(gates_module, "previous_pair_python", lambda *a: "python")
+    monkeypatch.setattr(
+        gates_module,
+        "run_metrics_report",
+        lambda *a, **k: {"partition_source": "test", "dataset_path": "dataset.h5"},
+    )
+    monkeypatch.setattr(
+        gates_module, "_download", lambda *a, **k: tmp_path / "wheel.whl"
+    )
+    for name in (
+        "installed_versions",
+        "wheel_hashes",
+        "core_compatibility",
+        "dataset_bytes",
+        "supported_years",
+        "budget_inputs",
+        "reform_contract",
+        "metrics_review",
+        "reform_responsiveness",
+    ):
+        monkeypatch.setattr(
+            gates_module,
+            name,
+            lambda *a, _name=name, **k: gates_module._result(
+                _name, "pass", "test", {"before_metadata": _name}
+            ),
+        )
+    monkeypatch.setattr(
+        gates_module,
+        "data_access",
+        lambda *a, **k: (*gates_module._result("data_access", "pass", "test", {}), {}),
+    )
+    resolved = SimpleNamespace(
+        pair=pair,
+        model_wheel=SimpleNamespace(
+            url="model", filename="model.whl", sha256=pair.model.wheel_sha256
+        ),
+        core_wheel=SimpleNamespace(
+            url="core", filename="core.whl", sha256=pair.core.wheel_sha256
+        ),
+        model_requires_core=">=3.0",
+    )
+    results, evidence = gates_module.run_candidate_gates(
+        resolved,
+        HARNESS,
+        config=config,
+        work_dir=tmp_path,
+        previous_certificate=_previous_identity(pair),
+        ledger_root=tmp_path,
+    )
+    mismatches = [
+        result.gate_id
+        for result in results
+        if result.evidence_sha256
+        != gates_module.evidence_sha256(evidence[result.gate_id])
+    ]
+    assert mismatches == []
+    assert snapshots == (["python"] if corrupt_baseline else [])
+    assert evidence["budget_inputs"]["previous_source"] == (
+        f"computed with policyengine {HARNESS.policyengine_version}"
+        if corrupt_baseline
+        else "ledger"
+    )
+
+
 @settings(max_examples=15, deadline=None)
 @given(
     present=st.sets(st.sampled_from(["age", "employment_income", "rent"]), min_size=1),

From f58b11ab4926f94d6c395b7337a904eb906f56fa Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:29:45 -0400
Subject: [PATCH 22/45] Attach the deferred-import lint suppression to the
 import statement

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 scripts/release_consumers.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/release_consumers.py b/scripts/release_consumers.py
index 3eefa409..57ab70cf 100644
--- a/scripts/release_consumers.py
+++ b/scripts/release_consumers.py
@@ -29,8 +29,8 @@
 
 import requests  # noqa: E402
 
-from policyengine.provenance.qualification_ledger import (
-    fetch_ledger_receipt,  # noqa: E402
+from policyengine.provenance.qualification_ledger import (  # noqa: E402
+    fetch_ledger_receipt,
 )
 from policyengine.provenance.uk_qualification import (  # noqa: E402
     release_dispatch_payload,

From d30e3f0c3b06b9d9c450cc0f589c4ae4e2c5210f Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Mon, 12 Oct 2026 08:35:19 -0400
Subject: [PATCH 23/45] Gate W1's full run on released policyengine-uk 2.126.12
 against the runner's own declarations

The fixture is the real contract report (673 pass, 6 pending d1344, 79
unsupported by design, 19 population rows); the test reads the coverage
from the merged runner module, so a stricter coverage rule cannot reject a
real full run unnoticed.

Co-Authored-By: Claude Opus 5.5 
---
 tests/fixtures/uk_contract/README.md          |    1 +
 .../full_released_uk_2.126.12.json            | 8005 +++++++++++++++++
 tests/test_uk_candidate_gates.py              |   42 +
 3 files changed, 8048 insertions(+)
 create mode 100644 tests/fixtures/uk_contract/full_released_uk_2.126.12.json

diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index e6d4e87f..60dcc40c 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -6,6 +6,7 @@ run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate
 
 - `pinned_uk_2.125.1_defects.json`: every case on policyengine-uk 2.125.1, the pinned model at the time, with `max_examples=2` and no dataset. The 66 failures and 35 errors are the dated-reform defects the contract was written to catch.
 - `full_allpass_uk_2.126.8.json`: the full run the gate expects. Every route and case, seed 0, `max_examples=20`, and population checks on the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`). The model was policyengine-uk 2.126.8 from the policyengine-uk#2305 branch with core 3.33.0, a development combination rather than a certified pair, so treat its `versions` as fixture metadata. Result: 267 pass, 6 pending decision d1344, 67 unsupported with reasons, both properties passing, 13 of 13 population checks; 20.6 minutes, peak RSS 2.7 GB.
+- `full_released_uk_2.126.12.json`: the full run on released policyengine-uk 2.126.12 with core 3.33.0 (12 October 2026, runner at main after #577, contract 1.0.0): every route and case, seed 0, `max_examples=20`, population checks on the certified `enhanced_frs_2024_25`. Result: 673 pass, 6 pending decision d1344, 79 unsupported with reasons, both properties passing, 19 of 19 population rows. A test gates it against the coverage the merged runner module declares.
 - `population_pass_max_examples_0.json`: population checks only, on the same dataset. It has no cases, and with `max_examples=0` its sampled properties did not run, so the gate treats it as an incomplete run.
 
 The only edits: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
diff --git a/tests/fixtures/uk_contract/full_released_uk_2.126.12.json b/tests/fixtures/uk_contract/full_released_uk_2.126.12.json
new file mode 100644
index 00000000..06e3f812
--- /dev/null
+++ b/tests/fixtures/uk_contract/full_released_uk_2.126.12.json
@@ -0,0 +1,8005 @@
+{
+ "cases": [
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "unchanged before 2027-28",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "held from 6 April 2027",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "april_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "april_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "prior law after 5 April 2028",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "baseline_isolation:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 174.300048828125,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": 174.29999999999967,
+   "holds": null,
+   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "finite_rate_change",
+   "check": "change:income_tax:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "the change has ended",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3486.0,
+   "case_id": "finite_rate_change",
+   "check": "unreformed_after_reform:income_tax:2028",
+   "expected": 3486.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "finite_rate_change",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 51330.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "expected": 51330.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 987.12,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "expected": 987.12,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39300.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "expected": 39300.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52390.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "expected": 52390.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 251.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "expected": 251.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1007.5,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "expected": 1007.5,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 40100.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "expected": 40100.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 53460.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "expected": 53460.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 256.92,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "expected": 256.92,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1028.08,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "expected": 1028.08,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "expected": 13630.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "expected": 41000.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 51330.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "expected": 51330.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 987.12,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "expected": 987.12,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 39300.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "expected": 39300.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 52390.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "expected": 52390.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 251.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "expected": 251.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1007.5,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "expected": 1007.5,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 40100.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "expected": 40100.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 53460.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "expected": 53460.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 256.92,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "expected": 256.92,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1028.08,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "expected": 1028.08,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "expected": 13630.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "expected": 41000.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 37700.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "decision_id": null,
+   "expected": 37700.0,
+   "holds": null,
+   "oracle": "frozen",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12570.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "decision_id": null,
+   "expected": 12570.0,
+   "holds": null,
+   "oracle": "aligned with the allowance",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 50270.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "decision_id": null,
+   "expected": 50270.0,
+   "holds": null,
+   "oracle": "allowance + basic rate limit",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 241.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "decision_id": null,
+   "expected": 241.73,
+   "holds": null,
+   "oracle": "12,570 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 966.73,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "decision_id": null,
+   "expected": 966.73,
+   "holds": null,
+   "oracle": "50,270 / 52, to the penny",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": null,
+   "expected": 13630.0,
+   "holds": null,
+   "oracle": "contract 1.0.0: prior law's projected path resumes",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "decision_id": "d1344",
+   "expected": 12830.0,
+   "holds": false,
+   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "decision_id": "d1344",
+   "expected": 38500.0,
+   "holds": false,
+   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pending"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "baseline_isolation:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 51330.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "expected": 51330.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 987.12,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "expected": 987.12,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39300.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "expected": 39300.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13090.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "expected": 13090.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 52390.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "expected": 52390.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 251.73,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "expected": 251.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1007.5,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "expected": 1007.5,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 40100.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "expected": 40100.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13360.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "expected": 13360.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 53460.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "expected": 53460.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 256.92,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "expected": 256.92,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1028.08,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "expected": 1028.08,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13630.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "expected": 13630.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 41000.0,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "expected": 41000.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 52.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2031",
+   "decision_id": null,
+   "expected": 52.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 104.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2032",
+   "decision_id": null,
+   "expected": 104.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 158.0,
+   "case_id": "extended_freeze",
+   "check": "change:income_tax:2033",
+   "decision_id": null,
+   "expected": 158.0,
+   "holds": null,
+   "oracle": "basic rate x (current law's allowance - 12,570)",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 3424.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2031",
+   "expected": 3424.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3372.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2032",
+   "expected": 3372.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 3318.39990234375,
+   "case_id": "extended_freeze",
+   "check": "unreformed_after_reform:income_tax:2033",
+   "expected": 3318.39990234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "extended_freeze",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "baseline_isolation:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "april_benefit_uprating",
+   "check": "variable:uc_standard_allowance:2029",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "held from April 2028",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "april_benefit_uprating",
+   "check": "change:uc_standard_allowance:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5426.7763671875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2029",
+   "expected": 5426.7763671875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "april_benefit_uprating",
+   "check": "unreformed_after_reform:uc_standard_allowance:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "april_benefit_uprating",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "baseline_isolation:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "change:uc_standard_allowance:2030",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5535.2998046875,
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": "unreformed_after_reform:uc_standard_allowance:2030",
+   "expected": 5535.2998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "bounded_change_on_uprated_benefit",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "variable:universal_credit:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "variable:universal_credit:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "variable:universal_credit:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "baseline_isolation:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "variable:universal_credit:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "variable:universal_credit:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "change:universal_credit:2028",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "prior law's uprated path resumes",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5098.7998046875,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2026",
+   "expected": 5098.7998046875,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": "unreformed_after_reform:universal_credit:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "uc_award_follows_the_standard_allowance",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 14560.0,
+   "case_id": "new_state_pension_rate",
+   "check": "variable:new_state_pension:2027",
+   "decision_id": null,
+   "expected": 14560.0,
+   "holds": null,
+   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "new_state_pension_rate",
+   "check": "change:new_state_pension:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 14560.0,
+   "case_id": "new_state_pension_rate",
+   "check": "variable:new_state_pension:2027",
+   "decision_id": null,
+   "expected": 14560.0,
+   "holds": null,
+   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "new_state_pension_rate",
+   "check": "change:new_state_pension:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 14560.0,
+   "case_id": "new_state_pension_rate",
+   "check": "variable:new_state_pension:2027",
+   "decision_id": null,
+   "expected": 14560.0,
+   "holds": null,
+   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "new_state_pension_rate",
+   "check": "change:new_state_pension:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "baseline_isolation:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 14560.0,
+   "case_id": "new_state_pension_rate",
+   "check": "variable:new_state_pension:2027",
+   "decision_id": null,
+   "expected": 14560.0,
+   "holds": null,
+   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "new_state_pension_rate",
+   "check": "change:new_state_pension:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 14560.0,
+   "case_id": "new_state_pension_rate",
+   "check": "variable:new_state_pension:2027",
+   "decision_id": null,
+   "expected": 14560.0,
+   "holds": null,
+   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "new_state_pension_rate",
+   "check": "change:new_state_pension:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 13036.9736328125,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2027",
+   "expected": 13036.9736328125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 12547.599609375,
+   "case_id": "new_state_pension_rate",
+   "check": "unreformed_after_reform:new_state_pension:2026",
+   "expected": 12547.599609375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "new_state_pension_rate",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 60.8197021484375,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2027",
+   "decision_id": null,
+   "expected": 60.81967213114759,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 140.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2028",
+   "decision_id": null,
+   "expected": 139.99999999999994,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+   "expected": 0.18,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 60.8197021484375,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2027",
+   "decision_id": null,
+   "expected": 60.81967213114759,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 140.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2028",
+   "decision_id": null,
+   "expected": 139.99999999999994,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+   "expected": 0.18,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18868852459016394,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "decision_id": null,
+   "expected": 0.18868852459016502,
+   "holds": null,
+   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "in force all year",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "decision_id": null,
+   "expected": 0.18,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 60.8197021484375,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2027",
+   "decision_id": null,
+   "expected": 60.81967213114759,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 140.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2028",
+   "decision_id": null,
+   "expected": 139.99999999999994,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "baseline_isolation:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+   "expected": 0.18,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.18000000000000002,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+   "expected": 0.18000000000000002,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 60.8197021484375,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2027",
+   "decision_id": null,
+   "expected": 60.81967213114759,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 140.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2028",
+   "decision_id": null,
+   "expected": 139.99999999999994,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2026",
+   "decision_id": null,
+   "expected": 0.0,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 60.8197021484375,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2027",
+   "decision_id": null,
+   "expected": 60.81967213114759,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 140.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "change:capital_gains_tax:2028",
+   "decision_id": null,
+   "expected": 139.99999999999994,
+   "holds": null,
+   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2026",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2027",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "mid_year_blended_rate",
+   "check": "unreformed_after_reform:capital_gains_tax:2028",
+   "expected": 1260.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "mid_year_blended_rate",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 13200.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "decision_id": null,
+   "expected": 13200.0,
+   "holds": null,
+   "oracle": "ITA 2007 s57(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 39600.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "decision_id": null,
+   "expected": 39600.0,
+   "holds": null,
+   "oracle": "ITA 2007 s21(3)",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 253.85,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "decision_id": null,
+   "expected": 253.85,
+   "holds": null,
+   "oracle": "aligned with the allowance, weekly",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 12830.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+   "expected": 12830.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 38500.0,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+   "expected": 38500.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 246.73,
+   "case_id": "september_cpi_moves_indexed_thresholds",
+   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+   "expected": 246.73,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "baseline_isolation:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "variable:uc_LCWRA_element:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5259.26806640625,
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+   "expected": 5259.26806640625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "uc_rebalancing_reform_after_data_load",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "unreformed_after_reform:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "unreformed_after_reform:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "baseline_isolation:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "unreformed_after_reform:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "unreformed_after_reform:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 1260.0,
+   "case_id": "structural_switch",
+   "check": "variable:marriage_allowance:2026",
+   "decision_id": null,
+   "expected": 1260.0,
+   "holds": null,
+   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0,
+   "case_id": "structural_switch",
+   "check": "unreformed_after_reform:marriage_allowance:2026",
+   "expected": 0.0,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "structural_switch",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 526.3154296875,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "change:vat:2026",
+   "decision_id": null,
+   "expected": 526.3157894736839,
+   "holds": null,
+   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 526.3154296875,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "change:vat:2026",
+   "decision_id": null,
+   "expected": 526.3157894736839,
+   "holds": null,
+   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 526.3154296875,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "change:vat:2026",
+   "decision_id": null,
+   "expected": 526.3157894736839,
+   "holds": null,
+   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_isolation:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "decision_id": null,
+   "expected": 5263.158203125,
+   "holds": null,
+   "oracle": "baseline_vat is the unreformed vat",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 526.3154296875,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "change:vat:2026",
+   "decision_id": null,
+   "expected": 526.3157894736839,
+   "holds": null,
+   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:baseline_vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "case_id": "baseline_vat_is_current_law",
+   "check": "baseline_equals:baseline_vat:2026",
+   "reason": "the policy route's output dataset holds the reformed run only",
+   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": 526.3154296875,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "change:vat:2026",
+   "decision_id": null,
+   "expected": 526.3157894736839,
+   "holds": null,
+   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5263.158203125,
+   "case_id": "baseline_vat_is_current_law",
+   "check": "unreformed_after_reform:vat:2026",
+   "expected": 5263.158203125,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "baseline_vat_is_current_law",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "modifier_then_parameter_changes",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "modifier_then_parameter_changes",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.0875,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.0875,
+   "holds": null,
+   "oracle": "set by the modifier",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before the change",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "in force on 30 April 2027",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "baseline_isolation:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.1075,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "expected": 0.1075,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "case_id": "parameter_changes_then_modifier",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "reason": "this route exposes outputs, not parameter values",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "unsupported"
+  },
+  {
+   "actual": -190.0,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2026",
+   "decision_id": null,
+   "expected": -190.00000000000003,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": -15.7001953125,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "change:income_tax:2027",
+   "decision_id": null,
+   "expected": -15.700000000000358,
+   "holds": null,
+   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2026",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 4507.25,
+   "case_id": "parameter_changes_then_modifier",
+   "check": "unreformed_after_reform:income_tax:2027",
+   "expected": 4507.25,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
+   "route": "country.scenario_parameter_changes",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
+   "case_id": "unknown_path",
+   "check": "rejected",
+   "expected": "an error matching 'new_credit'",
+   "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "case_id": "unknown_path",
+   "check": null,
+   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+   "reform_digest": null,
+   "route": "api.sim_api",
+   "status": "unsupported"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "fiscal year 2027",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "that year only",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "before 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "from 1 January 2027",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.21,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.21,
+   "holds": null,
+   "oracle": "onwards",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_bare_year_reform_from_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+   "route": "country.reform_from_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day is not 30 April",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "decision_id": null,
+   "expected": 0.2,
+   "holds": null,
+   "oracle": "one day only",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 0.2,
+   "case_id": "reading_single_day_dict",
+   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+   "expected": 0.2,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+   "route": "country.reform_dict",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+   "route": "wrapper.household",
+   "status": "pass"
+  },
+  {
+   "actual": 6000.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2027",
+   "decision_id": null,
+   "expected": 6000.0,
+   "holds": null,
+   "oracle": "\u00a3500 x 12",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 6240.0,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "variable:uc_standard_allowance:2028",
+   "decision_id": null,
+   "expected": 6240.0,
+   "holds": null,
+   "oracle": "\u00a3520 x 12",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5216.06103515625,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "unreformed_after_reform:uc_standard_allowance:2027",
+   "expected": 5216.06103515625,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": 5320.3740234375,
+   "case_id": "reading_effective_dates_reverse_order",
+   "check": "unreformed_after_reform:uc_standard_allowance:2028",
+   "expected": 5320.3740234375,
+   "oracle": "an unreformed simulation built after the reform equals one built before it",
+   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+   "route": "wrapper.policy",
+   "status": "pass"
+  },
+  {
+   "actual": "unchanged",
+   "case_id": "module_parameters_unchanged",
+   "check": "every parameter's dated values and metadata in processed, projected, statutory, system",
+   "expected": "policyengine-uk's shared parameters as they were before the run",
+   "oracle": "the shared parameter state's values, read before any reform ran",
+   "reform_digest": null,
+   "route": "all",
+   "status": "pass"
+  }
+ ],
+ "contract_id": "policyengine-uk/budget-reform-contract",
+ "contract_version": "1.0.0",
+ "dataset": {
+  "path": "",
+  "sha256": "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
+ },
+ "holds": true,
+ "max_examples": 20,
+ "population": [
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_baseline_isolation",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_query_order",
+   "detail": null,
+   "route": "unreformed",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_routes_agree",
+   "route": "country.reform_dict = country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0,
+    "2027_total_change": 205718.88776016235
+   },
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0,
+    "2027_total_change": 205718.88776016235
+   },
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_april_rate_change",
+   "detail": {
+    "2026_unchanged": true,
+    "2027_people_with_higher_tax": 1093,
+    "2027_people_with_lower_tax": 0,
+    "2027_total_change": 205718.88776016235
+   },
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_finite_change_expires",
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_uc_standard_allowance_plus_10",
+   "detail": {
+    "awards_higher": 105,
+    "awards_lower": 0,
+    "standard_allowance_scaled_10_percent": true
+   },
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_uc_standard_allowance_plus_10",
+   "detail": {
+    "awards_higher": 105,
+    "awards_lower": 0,
+    "standard_allowance_scaled_10_percent": true
+   },
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_uc_standard_allowance_plus_10",
+   "detail": {
+    "awards_higher": 105,
+    "awards_lower": 0,
+    "standard_allowance_scaled_10_percent": true
+   },
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_state_pension_plus_10",
+   "detail": {
+    "basic_and_new_scaled_10_percent": true,
+    "pensions_higher": 507,
+    "pensions_lower": 0
+   },
+   "route": "country.reform_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_state_pension_plus_10",
+   "detail": {
+    "basic_and_new_scaled_10_percent": true,
+    "pensions_higher": 507,
+    "pensions_lower": 0
+   },
+   "route": "country.scenario_parameter_changes",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  },
+  {
+   "check_id": "population_state_pension_plus_10",
+   "detail": {
+    "basic_and_new_scaled_10_percent": true,
+    "pensions_higher": 507,
+    "pensions_lower": 0
+   },
+   "route": "country.reform_from_dict",
+   "seed": 0,
+   "status": "pass",
+   "subsample_households": 1000
+  }
+ ],
+ "prior_law_option": "projected",
+ "properties": [
+  {
+   "engine": "hypothesis",
+   "examples_run": 20,
+   "property_id": "annual_values_match_the_oracle",
+   "status": "pass"
+  },
+  {
+   "engine": "hypothesis",
+   "examples_run": 20,
+   "property_id": "routes_agree_and_baselines_hold",
+   "status": "pass"
+  }
+ ],
+ "routes": [
+  "country.reform_dict",
+  "country.scenario_parameter_changes",
+  "country.reform_from_dict",
+  "wrapper.household",
+  "wrapper.policy",
+  "api.sim_api"
+ ],
+ "seed": 0,
+ "summary": {
+  "error": 0,
+  "fail": 0,
+  "pass": 673,
+  "pending": 6,
+  "unsupported": 79
+ },
+ "versions": {
+  "policyengine": "6.2.7",
+  "policyengine-core": "3.33.0",
+  "policyengine-uk": "2.126.12"
+ }
+}
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 17e057c9..1bf41f2e 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -788,6 +788,48 @@ def _run_contract(
     )[0]
 
 
+def test_the_released_models_full_run_passes_the_runners_own_declarations():
+    """W1's full run on released policyengine-uk 2.126.12, gated against the
+    coverage the merged runner module itself declares, so a stricter coverage
+    rule cannot reject a real full run unnoticed."""
+
+    import importlib
+    import types
+
+    from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
+
+    report = _fixture("full_released_uk_2.126.12.json")
+    if runner.CONTRACT_VERSION != report["contract_version"]:
+        pytest.skip(
+            f"the runner declares contract {runner.CONTRACT_VERSION}; refresh "
+            "tests/fixtures/uk_contract with a real full run"
+        )
+    proxy = types.ModuleType(runner.__name__)
+    proxy.__dict__.update(vars(runner))
+    proxy.run_budget_reform_contract = lambda **kwargs: report
+
+    def importer(name):
+        return proxy if name == runner.__name__ else importlib.import_module(name)
+
+    result = reform_contract(
+        entrypoint=ENTRY,
+        importer=importer,
+        expected_versions=report["versions"],
+        expected_dataset_sha256=CERTIFIED_SHA,
+        seed=0,
+        max_examples=20,
+        dataset_path=Path("enhanced_frs_2024_25.h5"),
+    )[0]
+    assert result.status == "pass", result.summary
+    assert result.details["counts"] == {
+        "pass": 673,
+        "fail": 0,
+        "error": 0,
+        "unsupported": 79,
+        "pending": 6,
+    }
+
+
 def test_w1_report_on_the_pinned_model_fails_on_its_defects():
     """W1's real report on policyengine-uk 2.125.1: 66 failures and 35 errors."""
 

From b44fa88a2fd4cadd7a0ceaa4644beba8a4bc5525 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Tue, 13 Oct 2026 09:45:08 -0400
Subject: [PATCH 24/45] Generate replay requests under country-import
 suppression; draft a ready PR before replacing its head

The request-replay child inherited POLICYENGINE_SKIP_COUNTRY_IMPORTS, so
pe.uk was None and every replay request failed; it now imports the UK
model directly. A forced re-qualification returns an already-ready
candidate PR to draft before pushing an unqualified head. Round-3
review H1 and M6.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 .github/workflows/certify-uk-release.yaml     |   8 ++
 .../provenance/uk_qualification.py            |   7 +-
 tests/test_uk_qualification_pipeline.py       | 135 ++++++++++++++++++
 3 files changed, 148 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/certify-uk-release.yaml b/.github/workflows/certify-uk-release.yaml
index 6940cd45..3c13b969 100644
--- a/.github/workflows/certify-uk-release.yaml
+++ b/.github/workflows/certify-uk-release.yaml
@@ -187,9 +187,17 @@ jobs:
       - name: Commit and push the candidate commit
         if: steps.duplicate.outputs.duplicate == 'false'
         env:
+          GH_TOKEN: ${{ steps.app-token.outputs.token }}
           BRANCH: ${{ needs.resolve.outputs.branch }}
           PAIR_ID: ${{ needs.resolve.outputs.pair_id }}
         run: |
+          # A forced attempt may replace an already qualified head. Revoke
+          # its ready status before exposing any new, unqualified commit.
+          ready_pr=$(gh pr list --head "$BRANCH" --state open --json number,isDraft \
+            --jq '.[] | select(.isDraft == false) | .number')
+          if [[ -n "$ready_pr" ]]; then
+            gh pr ready "$ready_pr" --undo
+          fi
           git add -A
           git -c user.name="policyengine-qualification[bot]" \
               -c user.email="qualification@policyengine.org" \
diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index 7ee5e9b0..7dd5870a 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -629,8 +629,11 @@ def expected_release_bundle(python: str, *, cwd: Path) -> dict[str, Optional[str
         [
             python,
             "-c",
-            "import json, policyengine as pe; "
-            "print(json.dumps(dict(pe.uk.uk_latest.release_bundle), sort_keys=True))",
+            # The CLI disables automatic country imports. Load the UK API
+            # explicitly so the flag cannot leave pe.uk unset and unrelated
+            # country models need not be initialized for this UK request.
+            "import json; from policyengine.tax_benefit_models.uk import uk_latest; "
+            "print(json.dumps(dict(uk_latest.release_bundle), sort_keys=True))",
         ],
         cwd=cwd,
         env=env,
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index 6717203e..4b212969 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -18,6 +18,7 @@
 
 import hashlib
 import json
+import os
 import shutil
 import subprocess
 import sys
@@ -419,6 +420,50 @@ def test_replay_request_is_valid_for_the_scorecard():
     assert again.request_id == request.request_id
 
 
+def test_the_real_cli_generates_replay_requests_despite_country_import_suppression(
+    tmp_path,
+):
+    """The real CLI can read the UK certificate despite automatic import suppression."""
+
+    from importlib.util import find_spec
+
+    if find_spec("policyengine_uk") is None:
+        pytest.skip("Replay request generation requires the installed UK model")
+    attempt = tmp_path / "attempt"
+    write_json(attempt / "candidate.json", {"pair": make_pair().canonical_payload()})
+    write_json(attempt / "harness.json", HARNESS.canonical_payload())
+    env = dict(os.environ)
+    env["POLICYENGINE_SKIP_COUNTRY_IMPORTS"] = "1"
+    env.pop("GITHUB_OUTPUT", None)
+    result = subprocess.run(
+        [
+            sys.executable,
+            str(REPO_ROOT / "scripts/check_uk_candidate.py"),
+            "request-replay",
+            "--attempt",
+            str(attempt),
+        ],
+        cwd=REPO_ROOT,
+        env=env,
+        capture_output=True,
+        text=True,
+        timeout=600,
+    )
+    assert result.returncode == 0, result.stdout + result.stderr
+    request = json.loads((attempt / "replay/request.json").read_text())
+    schema = json.loads(
+        (VENDORED_SCHEMAS / "qualification_request.v1.json").read_text()
+    )
+    jsonschema.Draft202012Validator(schema).validate(request)
+    candidate = request["candidate"]
+    assert candidate["policyengine"]["source"]["git"]["commit"] == HARNESS.git_commit
+    bundle = candidate["expected_release_bundle"]
+    record = BUNDLE["data_releases"]["uk"]
+    assert bundle["model_version"] == record["model_package"]["version"]
+    assert bundle["data_version"] == record["data_package"]["version"]
+    assert bundle["default_dataset"] == record["default_dataset"]
+
+
 def test_reading_replay_state():
     pair = make_pair()
     request = build_replay_request(
@@ -636,6 +681,95 @@ def test_a_forced_rerun_stages_a_new_attempt(tmp_path):
     assert attempt_key(pair, tmp_path, base_commit=base, force=True) == f"{base[:12]}-3"
 
 
+@pytest.mark.parametrize(
+    ("pr_state", "reset_fails"),
+    [("ready", False), ("draft", False), ("absent", False), ("ready", True)],
+)
+def test_the_workflow_drafts_existing_prs_before_replacing_their_head(
+    tmp_path, pr_state, reset_fails
+):
+    """Execute the workflow shell with local gh/git stand-ins and no remote writes."""
+
+    import yaml
+
+    workflow = yaml.safe_load(
+        (REPO_ROOT / ".github/workflows/certify-uk-release.yaml").read_text()
+    )
+    step = next(
+        step
+        for step in workflow["jobs"]["prepare"]["steps"]
+        if step.get("name") == "Commit and push the candidate commit"
+    )
+    state_path = tmp_path / "pr-state.json"
+    state_path.write_text(json.dumps({"status": pr_state}))
+    log_path = tmp_path / "commands.jsonl"
+    fake = f"""#!{sys.executable}
+import json
+import os
+import sys
+from pathlib import Path
+
+command = Path(sys.argv[0]).name
+args = sys.argv[1:]
+state_path = Path(os.environ["PR_STATE"])
+state = json.loads(state_path.read_text())
+with Path(os.environ["COMMAND_LOG"]).open("a") as log:
+    log.write(json.dumps([command, *args]) + "\\n")
+if command == "gh" and args[:2] == ["pr", "list"]:
+    if state["status"] == "ready":
+        print("574")
+elif command == "gh" and args[:2] == ["pr", "ready"]:
+    assert args[2:] == ["574", "--undo"]
+    if os.environ["RESET_FAILS"] == "1":
+        sys.exit(42)
+    state["status"] = "draft"
+    state_path.write_text(json.dumps(state))
+elif command == "git" and args[0] == "push":
+    if state["status"] == "ready":
+        sys.exit(91)
+"""
+    binary_dir = tmp_path / "bin"
+    binary_dir.mkdir()
+    for command in ("gh", "git"):
+        executable = binary_dir / command
+        executable.write_text(fake)
+        executable.chmod(0o755)
+    result = subprocess.run(
+        ["bash", "-e", "-o", "pipefail", "-c", step["run"]],
+        cwd=tmp_path,
+        env={
+            **os.environ,
+            "PATH": f"{binary_dir}{os.pathsep}{os.environ['PATH']}",
+            "BRANCH": "candidate/uk/2.126.8-1.58.0",
+            "PAIR_ID": "a" * 64,
+            "GH_TOKEN": "local-workflow-test",
+            "PR_STATE": str(state_path),
+            "COMMAND_LOG": str(log_path),
+            "RESET_FAILS": "1" if reset_fails else "0",
+        },
+        capture_output=True,
+        text=True,
+        timeout=30,
+    )
+    commands = [json.loads(line) for line in log_path.read_text().splitlines()]
+    pushes = [i for i, command in enumerate(commands) if command[:2] == ["git", "push"]]
+    resets = [
+        i for i, command in enumerate(commands) if command[:3] == ["gh", "pr", "ready"]
+    ]
+    if reset_fails:
+        assert result.returncode == 42, result.stdout + result.stderr
+        assert not pushes
+    else:
+        assert result.returncode == 0, result.stdout + result.stderr
+        assert len(pushes) == 1
+        if pr_state == "ready":
+            assert len(resets) == 1 and resets[0] < pushes[0]
+            assert json.loads(state_path.read_text())["status"] == "draft"
+        else:
+            assert not resets
+    assert step["env"]["GH_TOKEN"] == "${{ steps.app-token.outputs.token }}"
+
+
 # --- Attempt lifecycle -----------------------------------------------------------------
 
 
@@ -996,6 +1130,7 @@ def test_expected_release_bundle_uses_the_scorecard_certification_environment(
         "NO_PROXY": "huggingface.co",
         "no_proxy": "huggingface.co",
         "HTTPS_PROXY": "http://corporate:3128",
+        "POLICYENGINE_SKIP_COUNTRY_IMPORTS": "1",
     }
     env = uk_qualification.certification_environment(environ)
     assert env["PATH"] == "/usr/bin"

From 968272c9746b99e0baf06a0fbf8c95a79fef3f28 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Tue, 13 Oct 2026 09:45:09 -0400
Subject: [PATCH 25/45] Hold exact-pair certificates to their qualified model
 and build

Online acceptance could admit another runtime model or build through the
build-model, fingerprint and publisher-claim paths. Round-3 review H2.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/manifest.py    | 49 ++++++++++++++-------
 tests/test_qualified_pair_certification.py | 51 ++++++++++++++++++++++
 2 files changed, 85 insertions(+), 15 deletions(-)

diff --git a/src/policyengine/provenance/manifest.py b/src/policyengine/provenance/manifest.py
index 8f1a6446..05d062fe 100644
--- a/src/policyengine/provenance/manifest.py
+++ b/src/policyengine/provenance/manifest.py
@@ -470,18 +470,42 @@ def certify_data_release_compatibility(
             )
         raise exc
 
-    # An exact-pair certificate also restricts the core when the remote
-    # manifest offers a stronger model or fingerprint compatibility basis.
-    # Enforce that restriction before any online acceptance path can return.
+    # A remote build-model, fingerprint or publisher claim cannot broaden an
+    # exact-pair certificate beyond the model, core and recorded data build
+    # that qualification tested. Check them before any acceptance path returns.
     bundled_certification = country_manifest.certification
-    if bundled_certification is not None and not _runtime_core_is_certified(
-        bundled_certification, runtime_core_version
+    remote_build_id = (
+        data_release_manifest.build.build_id
+        if data_release_manifest.build is not None
+        else None
+    )
+    if (
+        bundled_certification is not None
+        and bundled_certification.compatibility_basis == "qualified_exact_pair"
     ):
-        raise ValueError(
-            "Data release manifest is not certified for the runtime core version "
-            f"{runtime_core_version} in country '{country_id}'; the exact pair "
-            f"requires {bundled_certification.certified_for_core_version}."
-        )
+        if bundled_certification.certified_for_model_version != runtime_model_version:
+            raise ValueError(
+                "Data release manifest is not certified for the runtime model "
+                f"version {runtime_model_version} in country '{country_id}'; "
+                "the exact pair requires "
+                f"{bundled_certification.certified_for_model_version}."
+            )
+        if not _runtime_core_is_certified(bundled_certification, runtime_core_version):
+            raise ValueError(
+                "Data release manifest is not certified for the runtime core "
+                f"version {runtime_core_version} in country '{country_id}'; "
+                "the exact pair requires "
+                f"{bundled_certification.certified_for_core_version}."
+            )
+        if (
+            bundled_certification.data_build_id is not None
+            and bundled_certification.data_build_id != remote_build_id
+        ):
+            raise ValueError(
+                "Data release manifest is not certified for the remote data "
+                f"build {remote_build_id} in country '{country_id}'; the exact "
+                f"pair requires {bundled_certification.data_build_id}."
+            )
     built_with_model = (
         data_release_manifest.build.built_with_model_package
         if data_release_manifest.build is not None
@@ -566,11 +590,6 @@ def certify_data_release_compatibility(
     # bundled certificate names the pair, and the ledger evidence for it is
     # enforced when the bundle is built (tests/test_certification_evidence.py).
     bundled_certification = country_manifest.certification
-    remote_build_id = (
-        data_release_manifest.build.build_id
-        if data_release_manifest.build is not None
-        else None
-    )
     if (
         bundled_certification is not None
         and bundled_certification.compatibility_basis == "qualified_exact_pair"
diff --git a/tests/test_qualified_pair_certification.py b/tests/test_qualified_pair_certification.py
index fc0f603c..3ce1d8cf 100644
--- a/tests/test_qualified_pair_certification.py
+++ b/tests/test_qualified_pair_certification.py
@@ -284,6 +284,57 @@ def test_online_other_core_is_refused(self):
         with pytest.raises(ValueError, match="not certified"):
             self._certify(_qualified(), "2.126.8", remote=_uk_manifest(), core="3.34.0")
 
+    @pytest.mark.parametrize(
+        ("runtime_model", "fingerprint", "claims"),
+        [
+            ("2.122.2", None, ()),
+            ("2.126.9", "sha256:build", ()),
+            ("2.126.9", None, ("==2.126.9",)),
+        ],
+        ids=["build-model", "fingerprint", "publisher-claim"],
+    )
+    def test_online_stronger_basis_cannot_bypass_qualified_model(
+        self, runtime_model, fingerprint, claims
+    ):
+        """The qualified core must not extend qualification to another model."""
+
+        with pytest.raises(ValueError, match="not certified.*model"):
+            self._certify(
+                _qualified(),
+                runtime_model,
+                remote=_uk_manifest(model_claims=claims),
+                fingerprint=fingerprint,
+            )
+
+    @pytest.mark.parametrize(
+        ("runtime_model", "fingerprint", "claims"),
+        [
+            ("2.122.2", None, ()),
+            ("2.126.8", "sha256:build", ()),
+            ("2.126.8", None, ("==2.126.8",)),
+        ],
+        ids=["build-model", "fingerprint", "publisher-claim"],
+    )
+    @pytest.mark.parametrize("remote_build", ["another-build", None])
+    def test_online_stronger_basis_cannot_bypass_qualified_build(
+        self, runtime_model, fingerprint, claims, remote_build
+    ):
+        remote = _uk_manifest(model_claims=claims)
+        remote.build.build_id = remote_build
+        with pytest.raises(ValueError, match="not certified.*data build"):
+            self._certify(
+                _qualified(model=runtime_model),
+                runtime_model,
+                remote=remote,
+                fingerprint=fingerprint,
+            )
+
+    def test_online_publisher_claim_cannot_bypass_missing_qualified_build(self):
+        remote = _uk_manifest(model_claims=("==2.126.8",))
+        remote.build = None
+        with pytest.raises(ValueError, match="not certified.*data build"):
+            self._certify(_qualified(), "2.126.8", remote=remote)
+
     @pytest.mark.parametrize(
         ("runtime_model", "fingerprint", "claims", "expected_basis"),
         [

From aa8d17b0505521e73f49eca564a7e3c06adbf7ae Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Tue, 13 Oct 2026 09:45:09 -0400
Subject: [PATCH 26/45] Accept only the runner's declared exemptions and
 require its run-level and isolation rows; validate metric baselines

Report-made unsupported rows, a deleted run-level row or deleted isolation
rows qualified a candidate, and a NaN or missing baseline passed the
review bounds. Exemptions and isolation coverage now come from the runner
module itself, and unusable or duplicate baselines need review. Round-3
review H3, H4 and M5.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py | 228 ++++++++++++++++++--
 tests/test_uk_candidate_gates.py            | 185 ++++++++++++++--
 tests/test_uk_candidate_metric_baselines.py | 110 ++++++++++
 3 files changed, 487 insertions(+), 36 deletions(-)
 create mode 100644 tests/test_uk_candidate_metric_baselines.py

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 4d03d799..16ddb053 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -646,19 +646,25 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
         checks: list[tuple[str, str, Optional[str]]] = []
         pending: dict[tuple[str, str, Optional[str]], str] = {}
         unsupported = getattr(module, "UNSUPPORTED_ROUTES", {})
+        country_routes = set(
+            getattr(
+                module,
+                "COUNTRY_ROUTES",
+                [route for route in routes if route.startswith("country.")],
+            )
+        )
+        unsupported_checks = {}
         for case in module.CASES:
             for route in (
                 case.routes if getattr(case, "routes", None) is not None else routes
             ):
                 if route in unsupported:
-                    checks.append((str(case.id), str(route), None))
+                    key = (str(case.id), str(route), None)
+                    checks.append(key)
+                    unsupported_checks[key] = unsupported[route]
                 elif getattr(case, "expect_error", None) is not None:
                     checks.append((str(case.id), str(route), "rejected"))
                 else:
-                    # W1 declares expected values in Case.checks. Additional
-                    # isolation/state rows are generated by runtime behavior,
-                    # without a declarative coverage matrix, so require every
-                    # declared value rather than inventing those extra rows.
                     for check in getattr(case, "checks", ()):
                         key = (
                             str(case.id),
@@ -668,16 +674,89 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
                         checks.append(key)
                         if getattr(check, "pending", None) is not None:
                             pending[key] = str(check.pending)
+                        # evaluate_case declares these per-check exemptions;
+                        # route-wide exemptions above replace the entire case.
+                        if check.target == "parameter" and route not in country_routes:
+                            unsupported_checks[key] = (
+                                "this route exposes outputs, not parameter values"
+                            )
+                        elif (
+                            check.target == "baseline_equals"
+                            and route == "wrapper.policy"
+                        ):
+                            unsupported_checks[key] = (
+                                "the policy route's output dataset holds the reformed run only"
+                            )
+
+                    # The runner has no machine-readable isolation matrix.
+                    # Derive its strongest coverage from _CountryRoute.run,
+                    # _WrapperHouseholdRoute.run and _WrapperPolicyRoute.run:
+                    # deduplicate requests; country baselines cover variable
+                    # requests and after-runs cover parameters and variables;
+                    # wrappers' after-runs cover exposed variables only.
+                    # baseline_equals also requests its expected variable on
+                    # country/household routes, but policy excludes that target.
+                    # Rejected/error and whole-route unsupported cases emit no
+                    # isolation rows. Every supported run also emits the shared
+                    # module parameter check, required independently below.
+                    requests = []
+                    for check in getattr(case, "checks", ()):
+                        if route not in country_routes and (
+                            check.target == "parameter"
+                            or (
+                                route == "wrapper.policy"
+                                and check.target == "baseline_equals"
+                            )
+                        ):
+                            continue
+                        kind = (
+                            "parameter" if check.target == "parameter" else "variable"
+                        )
+                        requests.append((kind, str(check.name), check.year))
+                        if check.target == "baseline_equals":
+                            requests.append(
+                                ("variable", str(check.expected), check.year)
+                            )
+                    for kind, name, year in dict.fromkeys(requests):
+                        if route in country_routes and kind == "variable":
+                            checks.append(
+                                (
+                                    str(case.id),
+                                    str(route),
+                                    f"baseline_isolation:{name}:{year}",
+                                )
+                            )
+                        checks.append(
+                            (
+                                str(case.id),
+                                str(route),
+                                f"unreformed_after_reform:{name}:{year}",
+                            )
+                        )
         return {
             "routes": routes,
             "pairs": pairs,
             "properties": [str(name) for name in module.PROPERTIES],
             "checks": checks,
+            "isolation_checks": {
+                (case, route, check)
+                for case, route, check in checks
+                if isinstance(check, str)
+                and check.startswith(
+                    ("baseline_isolation:", "unreformed_after_reform:")
+                )
+            },
             "pending_checks": pending,
             "pending_decisions": {
                 str(decision) for decision in getattr(module, "PENDING_DECISIONS", ())
             },
             "unsupported_routes": unsupported,
+            "unsupported_checks": unsupported_checks,
+            "run_pairs": (
+                [("module_parameters_unchanged", "all")]
+                if any(route not in unsupported for route in routes)
+                else []
+            ),
             "population": getattr(module, "POPULATION_CHECKS", None),
         }
     except AttributeError:
@@ -729,12 +808,13 @@ def reform_contract(
     ``fail`` when any case, sampled property or population check fails or
     errors. ``error`` when the report cannot be trusted as a full run of this
     candidate:
-    - it does not cover every declared case check on each route, every
-      declared population check and every sampled property, or a property
-      passed on fewer examples than requested;
+    - it does not cover every declared case check on each route, the runner's
+      isolation checks and run-level shared-parameter check, every declared
+      population check and every sampled property, or a property passed on
+      fewer examples than requested;
     - a property is pending, a pending row names no authorized decision,
-      or an unsupported case or
-      population check lacks its ``reason``;
+      or an unsupported case or population check has no runner-declared
+      exemption with the same ``reason``;
     - a sampled property did not run;
     - population checks are missing although a dataset was given;
     - the report names other versions, another dataset, seed or sample size
@@ -779,6 +859,21 @@ def reform_contract(
     unsupported: list[str] = []
     counts = dict.fromkeys(_CONTRACT_STATUSES, 0)
     coverage = _contract_coverage(runner_module)
+    population_exemptions = {}
+    population_module = None
+    if dataset_path is not None:
+        module_name = (
+            entrypoint.partition(":")[0]
+            if ":" in entrypoint
+            else entrypoint.rpartition(".")[0]
+        )
+        try:
+            population_module = importer(
+                module_name.rsplit(".", 1)[0] + ".budget_reform_population"
+            )
+            population_exemptions = getattr(population_module, "UNSUPPORTED_CHECKS", {})
+        except (ImportError, AttributeError):
+            pass
     allowed_pending = set(pending_decisions) | (
         coverage["pending_decisions"] if coverage else set()
     )
@@ -823,6 +918,38 @@ def reform_contract(
                     )
                 elif not row.get("reason"):
                     malformed.append(f"{label} is unsupported without a reason")
+                elif section == "cases":
+                    declared_reason = (
+                        coverage["unsupported_checks"].get(
+                            (
+                                str(row.get("case_id")),
+                                str(row.get("route")),
+                                row.get("check"),
+                            )
+                        )
+                        if coverage
+                        else None
+                    )
+                    if declared_reason is None:
+                        malformed.append(f"{label} is an undeclared unsupported check")
+                    elif row["reason"] != declared_reason:
+                        malformed.append(
+                            f"{label} has a different reason than its declared exemption"
+                        )
+                elif section == "population":
+                    # The population runner currently declares no per-check
+                    # exemptions. Its no-country-route sentinel cannot arise
+                    # in a full run; only explicit runner declarations exempt
+                    # a check, never a reason supplied by the report itself.
+                    declared_reason = population_exemptions.get(
+                        (str(row.get("check_id")), str(row.get("route")))
+                    )
+                    if declared_reason is None:
+                        malformed.append(f"{label} is an undeclared unsupported check")
+                    elif row["reason"] != declared_reason:
+                        malformed.append(
+                            f"{label} has a different reason than its declared exemption"
+                        )
                 unsupported.append(label)
             elif status != "pass":
                 malformed.append(f"{label} has unknown status {status!r}")
@@ -832,9 +959,12 @@ def reform_contract(
     # case on each route it runs on, and every sampled property with the
     # examples asked for. A report that drops any of it does not qualify.
     if coverage is None:
-        malformed.append(
+        # Lead with the missing runner declarations rather than truncating
+        # that root cause behind individual rows whose exemptions are unknown.
+        malformed.insert(
+            0,
             "the runner declares no ROUTES, CASES and PROPERTIES, so the "
-            "report's coverage cannot be checked"
+            "report's coverage cannot be checked",
         )
     else:
         reported_routes = [str(route) for route in report.get("routes") or []]
@@ -883,7 +1013,37 @@ def reform_contract(
                     for case, route, check in list(absent_checks)[:4]
                 )
             )
+        for case, route in coverage["run_pairs"]:
+            rows = [
+                row
+                for row in report.get("cases") or []
+                if row.get("case_id") == case and row.get("route") == route
+            ]
+            if len(rows) != 1:
+                malformed.append(
+                    f"run-level check {case}@{route} must have exactly one row"
+                )
+            elif rows[0].get("status") not in ("pass", "fail", "error"):
+                malformed.append(f"run-level check {case}@{route} did not run")
+            elif not (rows[0].get("check") or "").startswith(
+                "every parameter's dated values and metadata in "
+            ):
+                malformed.append(
+                    f"run-level check {case}@{route} does not identify the shared parameter check"
+                )
         for row in report.get("cases") or []:
+            key = (str(row.get("case_id")), str(row.get("route")), row.get("check"))
+            if key in coverage["isolation_checks"] and row.get("status") not in (
+                "pass",
+                "fail",
+                "error",
+            ):
+                # The runner emits pass/fail for isolation, never a methodology
+                # exemption. An explicit pending-decision override must not
+                # excuse a missing executed isolation check.
+                malformed.append(
+                    f"case {key[0]}@{key[1]} isolation check {key[2]} did not run"
+                )
             if row.get("route") in coverage["unsupported_routes"] and (
                 row.get("check") is not None or row.get("status") != "unsupported"
             ):
@@ -1168,18 +1328,41 @@ def compare_metric_reports(
         review.append("the model's fiscal partition changed")
     current = {_metric_key(row): row for row in candidate.get("metrics", [])}
     before_metrics = {_metric_key(row): row for row in previous.get("metrics", [])}
-    nonfinite = [
-        f"{key[0]} {key[1]}"
-        for key, row in current.items()
-        if row.get("value") is None
-        or not isinstance(row.get("value"), (int, float))
-        or not math.isfinite(float(row["value"]))
-    ]
-    if nonfinite:
-        problems.append(f"non-finite values: {', '.join(nonfinite[:8])}")
+    # Bounds are meaningful only when both sides contain usable values.
+    # In particular, NaN in the baseline must not silently skip a large move.
+    report_metric_rows = (
+        ("candidate", candidate.get("metrics", [])),
+        ("previous", previous.get("metrics", [])),
+    )
+    for name, rows in report_metric_rows:
+        metric_counts = Counter(_metric_key(row) for row in rows)
+        duplicate_metrics = sorted(
+            f"{key[0]} {key[1]}" for key, count in metric_counts.items() if count > 1
+        )
+        if duplicate_metrics:
+            problems.append(
+                f"the {name} report has duplicate metrics: "
+                + ", ".join(duplicate_metrics[:8])
+            )
+        nonfinite = [
+            f"{row.get('metric_id')} {row.get('year')}"
+            for row in rows
+            if row.get("value") is None
+            or not isinstance(row.get("value"), (int, float))
+            or not math.isfinite(float(row["value"]))
+        ]
+        if nonfinite:
+            problems.append(
+                f"the {name} report has non-finite values: {', '.join(nonfinite[:8])}"
+            )
     lost = sorted(f"{key[0]} {key[1]}" for key in set(before_metrics) - set(current))
     if lost:
         problems.append(f"metrics disappeared: {', '.join(lost[:8])}")
+    without_baseline = sorted(
+        f"{key[0]} {key[1]}" for key in set(current) - set(before_metrics)
+    )
+    if without_baseline:
+        review.append(f"metrics have no baseline: {', '.join(without_baseline[:8])}")
     moves = []
     for key, row in sorted(
         current.items(), key=lambda item: (item[0][0], item[0][1] or 0)
@@ -1189,7 +1372,7 @@ def compare_metric_reports(
             continue
         try:
             new_value, old_value = float(row["value"]), float(old["value"])
-        except (TypeError, ValueError):
+        except (KeyError, TypeError, ValueError):
             continue
         if not (math.isfinite(new_value) and math.isfinite(old_value)):
             continue
@@ -1222,6 +1405,7 @@ def compare_metric_reports(
         "newly_skipped_checks": newly_skipped,
         "unknown_status_checks": unknown_statuses,
         "lost_checks": lost_checks,
+        "metrics_without_baseline": without_baseline,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 1bf41f2e..c051d536 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -548,6 +548,13 @@ def _declared_coverage(source):
     from a report of a full run (each case limited to the routes it ran on)."""
 
     source = source or {}
+    from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
+
+    declared_checks = {
+        (case.id, check.target, check.name, check.year): check
+        for case in runner.CASES
+        for check in case.checks
+    }
     by_case = {}
     for row in source.get("cases") or []:
         by_case.setdefault(row.get("case_id"), []).append(row)
@@ -562,6 +569,13 @@ def _declared_coverage(source):
                         target=label.split(":")[0],
                         name=label.split(":")[1],
                         year=int(label.split(":")[2]),
+                        expected=getattr(
+                            declared_checks.get(
+                                (case, *label.split(":")[:2], int(label.split(":")[2]))
+                            ),
+                            "expected",
+                            None,
+                        ),
                         pending=next(
                             (
                                 row.get("decision_id")
@@ -582,6 +596,7 @@ def _declared_coverage(source):
                 else None,
             )
             for case, rows in by_case.items()
+            if case != "module_parameters_unchanged"
         ),
         "PROPERTIES": {
             row.get("property_id"): "" for row in source.get("properties") or []
@@ -637,6 +652,15 @@ def importer(name):
 ENTRY = "policyengine.tax_benefit_models.uk.budget_reform_contract:run_budget_reform_contract"
 
 
+def _run_level_row():
+    return {
+        "case_id": "module_parameters_unchanged",
+        "route": "all",
+        "check": "every parameter's dated values and metadata in system",
+        "status": "pass",
+    }
+
+
 @pytest.mark.parametrize(
     ("kwargs", "status"),
     [
@@ -651,7 +675,8 @@ def importer(name):
                             "case_id": "april",
                             "route": "wrapper.policy",
                             "status": "pass",
-                        }
+                        },
+                        _run_level_row(),
                     ],
                 }
             },
@@ -701,6 +726,7 @@ def importer(name):
                             "status": "pending",
                             "decision_id": "d1344",
                         },
+                        _run_level_row(),
                     ]
                 }
             },
@@ -764,7 +790,7 @@ def _recount(report: dict) -> dict:
 def _passing_report() -> dict:
     """W1's real full run: every route, 20 examples, the certified dataset."""
 
-    return _fixture("full_allpass_uk_2.126.8.json")
+    return _fixture("full_released_uk_2.126.12.json")
 
 
 def _run_contract(
@@ -781,24 +807,19 @@ def _run_contract(
             report=report,
             coverage=coverage if coverage is not None else _passing_report(),
         ),
-        expected_versions=versions
-        or {"policyengine-uk": "2.126.8", "policyengine-core": "3.33.0"},
+        expected_versions=versions or _passing_report()["versions"],
         expected_dataset_sha256=dataset_sha,
         **kwargs,
     )[0]
 
 
-def test_the_released_models_full_run_passes_the_runners_own_declarations():
-    """W1's full run on released policyengine-uk 2.126.12, gated against the
-    coverage the merged runner module itself declares, so a stricter coverage
-    rule cannot reject a real full run unnoticed."""
-
+def _run_released_contract(report, *, pending_decisions=()):
+    """Gate a fixture through the real runner's declarations and route logic."""
     import importlib
     import types
 
     from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
 
-    report = _fixture("full_released_uk_2.126.12.json")
     if runner.CONTRACT_VERSION != report["contract_version"]:
         pytest.skip(
             f"the runner declares contract {runner.CONTRACT_VERSION}; refresh "
@@ -811,7 +832,7 @@ def test_the_released_models_full_run_passes_the_runners_own_declarations():
     def importer(name):
         return proxy if name == runner.__name__ else importlib.import_module(name)
 
-    result = reform_contract(
+    return reform_contract(
         entrypoint=ENTRY,
         importer=importer,
         expected_versions=report["versions"],
@@ -819,7 +840,14 @@ def importer(name):
         seed=0,
         max_examples=20,
         dataset_path=Path("enhanced_frs_2024_25.h5"),
+        pending_decisions=pending_decisions,
     )[0]
+
+
+def test_the_released_models_full_run_passes_the_runners_own_declarations():
+    """W1's full run remains valid against the real runner's declarations."""
+
+    result = _run_released_contract(_fixture("full_released_uk_2.126.12.json"))
     assert result.status == "pass", result.summary
     assert result.details["counts"] == {
         "pass": 673,
@@ -830,6 +858,129 @@ def importer(name):
     }
 
 
+@pytest.mark.parametrize("section", ["cases", "population"])
+def test_supported_failures_cannot_be_relabelled_unsupported(section):
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report[section]
+        if row["status"] == "pass" and row["route"] == "country.reform_dict"
+    )
+    row["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    row.update(status="unsupported", reason="this candidate does not support it")
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any(
+        "undeclared unsupported" in problem for problem in result.details["problems"]
+    )
+
+
+def test_population_cannot_exempt_every_required_check():
+    report = _fixture("full_released_uk_2.126.12.json")
+    assert len(report["population"]) == 19
+    for row in report["population"]:
+        row.update(status="unsupported", reason="no population support")
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert (
+        len([p for p in result.details["problems"] if "undeclared unsupported" in p])
+        == 19
+    )
+
+
+@pytest.mark.parametrize("route", ["api.sim_api", "wrapper.household"])
+def test_declared_case_exemptions_require_the_runners_reason(route):
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report["cases"]
+        if row["route"] == route and row["status"] == "unsupported"
+    )
+    row["reason"] = "a different exemption"
+    result = _run_released_contract(report)
+    assert result.status == "error", result.summary
+    assert any("different reason" in p for p in result.details["problems"])
+
+
+def test_deleting_a_failed_run_level_check_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report["cases"]
+        if row["case_id"] == "module_parameters_unchanged"
+    )
+    row["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    report["cases"].remove(row)
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any(
+        "module_parameters_unchanged@all" in p for p in result.details["problems"]
+    )
+
+
+@pytest.mark.parametrize(
+    ("route", "check_prefix"),
+    [
+        ("country.reform_dict", "baseline_isolation:"),
+        ("country.scenario_parameter_changes", "baseline_isolation:"),
+        ("country.reform_from_dict", "baseline_isolation:"),
+        ("country.reform_dict", "unreformed_after_reform:gov."),
+        ("country.reform_dict", "unreformed_after_reform:income_tax:"),
+        ("wrapper.household", "unreformed_after_reform:"),
+        ("wrapper.policy", "unreformed_after_reform:"),
+    ],
+)
+def test_each_runner_isolation_row_is_required(route, check_prefix):
+    report = _fixture("full_released_uk_2.126.12.json")
+    omitted = next(
+        row
+        for row in report["cases"]
+        if row["route"] == route and (row.get("check") or "").startswith(check_prefix)
+    )
+    report["cases"].remove(omitted)
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any(omitted["check"] in p for p in result.details["problems"])
+
+
+def test_deleting_all_runner_isolation_rows_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    report["cases"] = [
+        row
+        for row in report["cases"]
+        if not (row.get("check") or "").startswith(
+            ("baseline_isolation:", "unreformed_after_reform:")
+        )
+    ]
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any("baseline_isolation:" in p for p in result.details["problems"])
+
+
+@pytest.mark.parametrize(
+    "check_prefix", ["baseline_isolation:", "unreformed_after_reform:"]
+)
+def test_failing_isolation_checks_cannot_be_relabelled_pending(check_prefix):
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report["cases"]
+        if row["route"] == "country.reform_dict"
+        and (row.get("check") or "").startswith(check_prefix)
+    )
+    row["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    row.update(status="pending", decision_id="d1344")
+    result = _run_released_contract(_recount(report), pending_decisions=("d1344",))
+    assert result.status == "error", result.summary
+    assert any(
+        "isolation check" in p and "did not run" in p
+        for p in result.details["problems"]
+    )
+
+
 def test_w1_report_on_the_pinned_model_fails_on_its_defects():
     """W1's real report on policyengine-uk 2.125.1: 66 failures and 35 errors."""
 
@@ -844,7 +995,13 @@ def test_w1_report_on_the_pinned_model_fails_on_its_defects():
     )
     assert result.status == "fail"
     assert result.summary.startswith("101 contract row(s) failed")
-    assert result.details["problems"] == []
+    # This historical runner predates the always-emitted run-level check and
+    # after-run isolation rows. Its failures remain decisive; current coverage
+    # validation also correctly identifies those absent rows.
+    assert any("declared case check(s)" in p for p in result.details["problems"])
+    assert any(
+        "module_parameters_unchanged@all" in p for p in result.details["problems"]
+    )
 
 
 def test_w1_population_run_alone_is_incomplete():
@@ -859,11 +1016,11 @@ def test_w1_population_run_alone_is_incomplete():
 
 
 def test_w1_full_run_passes():
-    """W1's real all-pass report: 267 pass, 6 pending d1344, 67 unsupported."""
+    """W1's real all-pass report: 673 pass, 6 pending d1344, 79 unsupported."""
 
     result = _run_contract(_passing_report())
     assert result.status == "pass", result.summary
-    assert "every case, property and population check passed (267)" in result.summary
+    assert "every case, property and population check passed (673)" in result.summary
     assert "6 pending a methodology call" in result.summary
     assert result.details["problems"] == []
 
diff --git a/tests/test_uk_candidate_metric_baselines.py b/tests/test_uk_candidate_metric_baselines.py
new file mode 100644
index 00000000..712a65a6
--- /dev/null
+++ b/tests/test_uk_candidate_metric_baselines.py
@@ -0,0 +1,110 @@
+"""Review bounds require usable baseline values for each candidate metric."""
+
+import copy
+
+import pytest
+
+from policyengine.provenance.uk_candidate import compare_metric_reports, metrics_review
+
+BOUNDS = {"default": {"relative": 0.02, "absolute": 5e8}}
+
+
+def _report():
+    return {
+        "status": "ok",
+        "metrics_version": "m1",
+        "partition_version": "p1",
+        "metrics": [
+            {
+                "metric_id": "income_tax",
+                "year": 2027,
+                "kind": "receipt",
+                "value": 3e11,
+            },
+            {
+                "metric_id": "relative_poverty",
+                "year": 2027,
+                "kind": "poverty",
+                "value": 0.17,
+            },
+        ],
+        "identities": [{"identity_id": "weights:household", "status": "pass"}],
+    }
+
+
+@pytest.mark.parametrize(
+    "baseline_value", [float("nan"), float("inf"), -float("inf"), None, "invalid"]
+)
+def test_unusable_baseline_cannot_claim_a_large_move_is_within_bounds(baseline_value):
+    candidate, previous = _report(), _report()
+    candidate["metrics"][0]["value"] = 1e12
+    previous["metrics"][0]["value"] = baseline_value
+
+    status, summary, _ = compare_metric_reports(candidate, previous, BOUNDS)
+
+    assert status == "fail"
+    assert "previous" in summary and "non-finite" in summary
+    gate, _ = metrics_review(
+        candidate_report=candidate, previous_report=previous, bounds=BOUNDS
+    )
+    assert gate.status == "fail"
+    assert gate.evidence_sha256
+
+
+def test_a_baseline_row_without_a_value_cannot_pass():
+    candidate, previous = _report(), _report()
+    del previous["metrics"][0]["value"]
+    assert compare_metric_reports(candidate, previous, BOUNDS)[0] == "fail"
+
+
+def test_a_metric_without_a_baseline_requires_review():
+    candidate, previous = _report(), _report()
+    previous["metrics"] = previous["metrics"][1:]
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "needs_review"
+    assert "no baseline" in summary and "income_tax" in summary
+    assert evidence["metrics_without_baseline"] == ["income_tax 2027"]
+
+
+@pytest.mark.parametrize("side", ["candidate", "previous"])
+def test_a_duplicate_metric_cannot_hide_an_unusable_value(side):
+    candidate, previous = _report(), _report()
+    report = candidate if side == "candidate" else previous
+    report["metrics"].insert(0, {**report["metrics"][0], "value": float("nan")})
+    status, summary, _ = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "fail"
+    assert "duplicate metrics" in summary and side in summary
+
+
+def test_duplicate_finite_baselines_cannot_select_the_most_favourable_comparison():
+    candidate, previous = _report(), _report()
+    candidate["metrics"][0]["value"] = 1e12
+    previous["metrics"].append({**previous["metrics"][0], "value": 1e12})
+    status, summary, _ = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "fail"
+    assert "previous report has duplicate metrics: income_tax 2027" in summary
+
+
+def test_an_unusable_cross_report_cannot_pass_either_review_step():
+    candidate, previous, cross = _report(), _report(), _report()
+    cross["metrics"][0]["value"] = float("nan")
+    gate, evidence = metrics_review(
+        candidate_report=candidate,
+        previous_report=previous,
+        cross_report=cross,
+        bounds=BOUNDS,
+    )
+    assert gate.status == "fail"
+    assert "model_only" in evidence and "data_only" in evidence
+    assert "data_only: the previous report has non-finite" in gate.summary
+
+
+def test_valid_baselines_preserve_bounds_and_do_not_mutate_reports():
+    candidate, previous = _report(), _report()
+    original = copy.deepcopy((candidate, previous))
+    assert compare_metric_reports(candidate, previous, BOUNDS)[0] == "pass"
+    assert (candidate, previous) == original
+    candidate["metrics"][0]["value"] = 1e12
+    status, _, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "needs_review"
+    assert evidence["moves_beyond_bounds"][0]["metric_id"] == "income_tax"

From 72d263dd986e2ab26f2f9127dc4f0bb386994e2d Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Wed, 14 Oct 2026 08:21:51 -0400
Subject: [PATCH 27/45] Give each contract assertion an id and declare full-run
 population coverage

Two additions to the UK Budget reform contract runner (W1's files) that the
qualification gate (#574) needs. Neither changes any check's status,
expected value or actual value:
- Each case row carries assertion_id, its check label plus its index in the
  case's checks, so two assertions with the same label (one mandatory, one
  pending) stay distinct in a report.
- budget_reform_population.population_check_routes(routes) declares the
  exact (check, route) rows a full population run emits.

tests/test_assertion_ids_change_no_verdict compares every case, route and
three fake routes' rows, without assertion_id, with rows recorded from the
runner on main before this change (tests/fixtures/uk_contract/
evaluate_case_rows.json, 1,322 rows), so any change to a verdict fails it.
A population test checks the declared coverage equals what a run emits.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 .../uk/budget_reform_contract.py              |   9 +-
 .../uk/budget_reform_population.py            |  29 +++++
 .../uk_contract/evaluate_case_rows.json       |   1 +
 tests/test_uk_budget_reform_contract.py       |  52 +++++++++
 tests/uk_contract_row_scenarios.py            | 103 ++++++++++++++++++
 5 files changed, 193 insertions(+), 1 deletion(-)
 create mode 100644 tests/fixtures/uk_contract/evaluate_case_rows.json
 create mode 100644 tests/uk_contract_row_scenarios.py

diff --git a/src/policyengine/tax_benefit_models/uk/budget_reform_contract.py b/src/policyengine/tax_benefit_models/uk/budget_reform_contract.py
index 4ca13fac..63b55f06 100644
--- a/src/policyengine/tax_benefit_models/uk/budget_reform_contract.py
+++ b/src/policyengine/tax_benefit_models/uk/budget_reform_contract.py
@@ -1539,8 +1539,11 @@ def evaluate_case(
             )
         ]
     rows = []
-    for check in case.checks:
+    for assertion_index, check in enumerate(case.checks):
         label = f"{check.target}:{check.name}:{check.year}"
+        # Several assertions can read the same value under different oracles.
+        # The index identifies each declared assertion even when labels collide.
+        assertion_id = f"{label}:{assertion_index}"
         if check.target == "parameter" and route not in COUNTRY_ROUTES:
             rows.append(
                 _row(
@@ -1548,6 +1551,7 @@ def evaluate_case(
                     route,
                     digest,
                     check=label,
+                    assertion_id=assertion_id,
                     status=UNSUPPORTED,
                     reason="this route exposes outputs, not parameter values",
                 )
@@ -1560,6 +1564,7 @@ def evaluate_case(
                     route,
                     digest,
                     check=label,
+                    assertion_id=assertion_id,
                     status=UNSUPPORTED,
                     reason="the policy route's output dataset holds the reformed run only",
                 )
@@ -1592,6 +1597,7 @@ def evaluate_case(
                     route,
                     digest,
                     check=label,
+                    assertion_id=assertion_id,
                     status=PENDING if check.pending is not None else ERROR,
                     decision_id=check.pending,
                     detail=repr(error)[:500],
@@ -1608,6 +1614,7 @@ def evaluate_case(
                 route,
                 digest,
                 check=label,
+                assertion_id=assertion_id,
                 status=status,
                 expected=float(expected),
                 actual=actual,
diff --git a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
index 9ed54b55..9a0a7974 100644
--- a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
+++ b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
@@ -63,6 +63,35 @@
 )
 RESPONSE_YEAR = 2027
 
+COUNTRY_POPULATION_CHECKS = (
+    "population_baseline_isolation",
+    "population_april_rate_change",
+    "population_finite_change_expires",
+    "population_uc_standard_allowance_plus_10",
+    "population_state_pension_plus_10",
+)
+UNREFORMED_POPULATION_CHECKS = (
+    "population_baseline_isolation",
+    "population_query_order",
+)
+
+
+def population_check_routes(routes: Sequence[str]) -> tuple[tuple[str, str], ...]:
+    """The complete full-run coverage, including comparison and baseline routes."""
+    country = [route for route in routes if route.startswith("country.")]
+    if not country:
+        return (("population", "-"),)
+    return (
+        tuple(
+            (check, route) for check in COUNTRY_POPULATION_CHECKS for route in country
+        )
+        + tuple((check, "unreformed") for check in UNREFORMED_POPULATION_CHECKS)
+        + tuple(
+            ("population_routes_agree", f"{country[0]} = {route}")
+            for route in country[1:]
+        )
+    )
+
 
 def plus_ten_percent(paths: Sequence[str]) -> dict:
     """Each parameter 10% above current law for the response year."""
diff --git a/tests/fixtures/uk_contract/evaluate_case_rows.json b/tests/fixtures/uk_contract/evaluate_case_rows.json
new file mode 100644
index 00000000..702ae33f
--- /dev/null
+++ b/tests/fixtures/uk_contract/evaluate_case_rows.json
@@ -0,0 +1 @@
+[{"actual": 645.913637, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 590.141163, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -59.58982299999991, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "finite_rate_change", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 44.177444, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 263.402723, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 441.346756, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 576.142235, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 136.71218800000003, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 219.171255, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 153.189373, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 956.790433, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 77.025182, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 476.674451, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 671.131436, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 644.567674, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 686.806713, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 403.383625, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 820.63996, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 643.463151, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 245.362965, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 176.381387, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 72.076954, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.reform_dict", "status": "pending", "variant": "hashed"}, {"actual": 696.472094, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.reform_dict", "status": "pending", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 44.177444, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 263.402723, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 441.346756, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 576.142235, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 136.71218800000003, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 219.171255, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 153.189373, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 956.790433, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 77.025182, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 476.674451, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 671.131436, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 644.567674, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 686.806713, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 403.383625, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 820.63996, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 643.463151, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 245.362965, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 176.381387, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 72.076954, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.scenario_parameter_changes", "status": "pending", "variant": "hashed"}, {"actual": 696.472094, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.scenario_parameter_changes", "status": "pending", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 44.177444, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 263.402723, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 441.346756, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 576.142235, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 136.71218800000003, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 219.171255, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 153.189373, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 956.790433, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 77.025182, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 476.674451, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 671.131436, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 644.567674, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 686.806713, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 403.383625, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 820.63996, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 643.463151, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 245.362965, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 176.381387, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 72.076954, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 898.750354, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.reform_from_dict", "status": "pending", "variant": "hashed"}, {"actual": 696.472094, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.reform_from_dict", "status": "pending", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 136.71218800000003, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 644.567674, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 72.076954, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 136.71218800000003, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 644.567674, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 72.076954, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "extended_freeze", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 330.287127, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 202.243466, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -552.657047, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 202.243466, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -552.657047, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 202.243466, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -552.657047, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 202.243466, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -552.657047, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 202.243466, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -552.657047, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "april_benefit_uprating", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 330.287127, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 133.182723, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -229.11419100000006, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 133.182723, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -229.11419100000006, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 133.182723, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -229.11419100000006, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 133.182723, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -229.11419100000006, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 133.182723, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -229.11419100000006, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "bounded_change_on_uprated_benefit", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 883.417699, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -495.80258999999995, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 806.950692, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 883.417699, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -495.80258999999995, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 806.950692, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 883.417699, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -495.80258999999995, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 806.950692, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 883.417699, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -495.80258999999995, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 806.950692, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 883.417699, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -495.80258999999995, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 806.950692, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 74.665262, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -205.02065900000002, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 74.665262, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -205.02065900000002, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 74.665262, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -205.02065900000002, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 74.665262, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": -205.02065900000002, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 74.665262, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": -205.02065900000002, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "new_state_pension_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 201.021203, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 169.599276, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 871.45993, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": -175.13142100000005, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 469.078429, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 613.976534, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 201.021203, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 169.599276, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 871.45993, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": -175.13142100000005, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 469.078429, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 613.976534, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 201.021203, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 169.599276, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 871.45993, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": -175.13142100000005, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 469.078429, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 613.976534, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": -175.13142100000005, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 469.078429, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 613.976534, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": -175.13142100000005, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 469.078429, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 613.976534, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "mid_year_blended_rate", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 44.177444, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 44.177444, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 44.177444, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 117.651344, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 19.665556, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "september_cpi_moves_indexed_thresholds", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 521.369962, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 521.369962, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 521.369962, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 521.369962, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 521.369962, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 413.826244, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 413.826244, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 413.826244, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 413.826244, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 413.826244, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "structural_switch", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 869.699003, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 518.752611, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 320.54442900000004, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 869.699003, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 518.752611, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 320.54442900000004, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 869.699003, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 518.752611, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 320.54442900000004, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 869.699003, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 518.752611, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 320.54442900000004, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 320.54442900000004, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "baseline_vat_is_current_law", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 853.707753, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 853.707753, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 853.707753, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "modifier_then_parameter_changes", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 853.707753, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 853.707753, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 853.707753, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 914.41469, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 0.4343870000000152, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 351.81676099999993, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "parameter_changes_then_modifier", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "unknown_path", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 645.913637, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 645.913637, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_bare_year_reform_from_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 590.141163, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 837.048597, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_single_day_dict", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 330.287127, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "hashed"}, {"actual": 330.287127, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 768.927933, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "baseline_isolation:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2027", "decision_id": null, "expected": 5.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "hashed"}, {"actual": 5.0, "case_id": "reading_effective_dates_reverse_order", "check": "unreformed_after_reform:income_tax:2028", "decision_id": null, "expected": 6.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "hashed"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "hashed"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "finite_rate_change", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2027", "decision_id": null, "expected": 299.9979999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "finite_rate_change", "check": "change:income_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.reform_dict", "status": "pending", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.reform_dict", "status": "pending", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.scenario_parameter_changes", "status": "pending", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.scenario_parameter_changes", "status": "pending", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": 37700.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": 12570.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": 50270.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": 241.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": 966.73, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": "d1344", "expected": 15090.0, "holds": false, "route": "country.reform_from_dict", "status": "pending", "variant": "unchanged"}, {"actual": 0.2, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": "d1344", "expected": 45300.0, "holds": false, "route": "country.reform_from_dict", "status": "pending", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2031", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2032", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "extended_freeze", "check": "change:income_tax:2033", "decision_id": null, "expected": -2513.96, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "april_benefit_uprating", "check": "variable:uc_standard_allowance:2029", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "april_benefit_uprating", "check": "change:uc_standard_allowance:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "bounded_change_on_uprated_benefit", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "bounded_change_on_uprated_benefit", "check": "change:uc_standard_allowance:2030", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "variable:universal_credit:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "uc_award_follows_the_standard_allowance", "check": "change:universal_credit:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "new_state_pension_rate", "check": "variable:new_state_pension:2027", "decision_id": null, "expected": 14560.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "new_state_pension_rate", "check": "change:new_state_pension:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": 0.18868852459016502, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": 0.18, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": "parameter:gov.hmrc.cgt.basic_rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2026", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2027", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "mid_year_blended_rate", "check": "change:capital_gains_tax:2028", "decision_id": null, "expected": 0.0, "holds": null, "route": "wrapper.policy", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": 13200.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": 39600.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": 253.85, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "uc_rebalancing_reform_after_data_load", "check": "variable:uc_LCWRA_element:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "structural_switch", "check": "variable:marriage_allowance:2026", "decision_id": null, "expected": 1260.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 1000.0, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 1000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 1000.0, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": 1000.0, "holds": null, "route": "wrapper.household", "status": "pass", "variant": "unchanged"}, {"actual": 0.0, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": "baseline_equals:baseline_vat:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "baseline_vat_is_current_law", "check": "change:vat:2026", "decision_id": null, "expected": 999.9999999999994, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "modifier_then_parameter_changes", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": 0.0875, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2026", "decision_id": null, "expected": -1124.9775000000002, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 0.0, "case_id": "parameter_changes_then_modifier", "check": "change:income_tax:2027", "decision_id": null, "expected": -824.9795000000008, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": "accepted", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "unknown_path", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.21, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.scenario_parameter_changes", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": 0.2, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": 0.2, "holds": null, "route": "country.reform_from_dict", "status": "pass", "variant": "unchanged"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_single_day_dict", "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028", "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.household", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2027", "decision_id": null, "expected": 6000.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": 1000.0, "case_id": "reading_effective_dates_reverse_order", "check": "variable:uc_standard_allowance:2028", "decision_id": null, "expected": 6240.0, "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "unchanged"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "unchanged"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "finite_rate_change", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "extended_freeze", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "april_benefit_uprating", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "bounded_change_on_uprated_benefit", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_award_follows_the_standard_allowance", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "new_state_pension_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "mid_year_blended_rate", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "september_cpi_moves_indexed_thresholds", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "uc_rebalancing_reform_after_data_load", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "structural_switch", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "baseline_vat_is_current_law", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "modifier_then_parameter_changes", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "parameter_changes_then_modifier", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": "RuntimeError: route failed", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_dict", "status": "fail", "variant": "error"}, {"actual": "RuntimeError: route failed", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.scenario_parameter_changes", "status": "fail", "variant": "error"}, {"actual": "RuntimeError: route failed", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "country.reform_from_dict", "status": "fail", "variant": "error"}, {"actual": "RuntimeError: route failed", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.household", "status": "fail", "variant": "error"}, {"actual": "RuntimeError: route failed", "case_id": "unknown_path", "check": "rejected", "decision_id": null, "expected": "an error matching 'new_credit'", "holds": null, "route": "wrapper.policy", "status": "fail", "variant": "error"}, {"actual": null, "case_id": "unknown_path", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_bare_year_reform_from_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_single_day_dict", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.scenario_parameter_changes", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "country.reform_from_dict", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.household", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "wrapper.policy", "status": "error", "variant": "error"}, {"actual": null, "case_id": "reading_effective_dates_reverse_order", "check": null, "decision_id": null, "expected": null, "holds": null, "route": "api.sim_api", "status": "unsupported", "variant": "error"}]
diff --git a/tests/test_uk_budget_reform_contract.py b/tests/test_uk_budget_reform_contract.py
index d07e91c9..a4113e2b 100644
--- a/tests/test_uk_budget_reform_contract.py
+++ b/tests/test_uk_budget_reform_contract.py
@@ -177,6 +177,52 @@ def test_passing_failing_pending_and_isolation_rows(monkeypatch):
     assert rows["baseline_isolation:income_tax:2027"]["status"] == "pass"
 
 
+@pytest.mark.parametrize("route", ["country.reform_dict", "wrapper.household"])
+def test_assertions_with_the_same_value_request_have_distinct_identities(
+    monkeypatch, route
+):
+    from dataclasses import replace
+
+    duplicate = replace(
+        CASE,
+        checks=(
+            Check("parameter", RATE, 2027, 0.21, "mandatory oracle"),
+            Check("parameter", RATE, 2027, 0.20, "pending oracle", pending="d1344"),
+        ),
+    )
+    fake(
+        monkeypatch,
+        FakeRoute(reformed={("parameter", RATE, 2027): 0.21}, unreformed={}),
+    )
+    rows = evaluate_case(duplicate, route)
+    assert [row["status"] for row in rows] == (
+        ["pass", "pending"]
+        if route == "country.reform_dict"
+        else ["unsupported", "unsupported"]
+    )
+    assert len({row["check"] for row in rows}) == 1
+    assert all(
+        isinstance(row["assertion_id"], str) and row["assertion_id"] for row in rows
+    )
+    assert len({row["assertion_id"] for row in rows}) == 2
+
+
+def test_assertion_ids_change_no_verdict():
+    """Labelling rows changes no status, expected value or actual value.
+
+    The fixture holds the rows the runner produced on main 9d0c7c57, before
+    rows carried an ``assertion_id``, for every case and route under three
+    fake routes (see ``tests/uk_contract_row_scenarios.py``).
+    """
+
+    from pathlib import Path
+
+    from tests.uk_contract_row_scenarios import scenario_rows
+
+    fixture = Path(__file__).parent / "fixtures/uk_contract/evaluate_case_rows.json"
+    assert scenario_rows(contract, CASES) == json.loads(fixture.read_text())
+
+
 def test_a_wrong_value_fails_and_a_leaking_baseline_fails(monkeypatch):
     fake(
         monkeypatch,
@@ -502,6 +548,7 @@ def test_the_subsample_is_deterministic_and_keeps_whole_households(tmp_path):
 def test_population_checks_hold_on_a_tiny_dataset(tmp_path):
     pytest.importorskip("policyengine_uk.utils.dated_reforms")
     from policyengine.tax_benefit_models.uk.budget_reform_population import (
+        population_check_routes,
         run_population_checks,
     )
 
@@ -511,6 +558,11 @@ def test_population_checks_hold_on_a_tiny_dataset(tmp_path):
         seed=0,
     )
     assert rows and all(row["status"] == "pass" for row in rows), rows
+    from collections import Counter
+
+    assert Counter((row["check_id"], row["route"]) for row in rows) == Counter(
+        population_check_routes(list(contract.COUNTRY_ROUTES))
+    )
 
 
 def test_responsiveness_checks_fail_with_no_award_to_move(tmp_path):
diff --git a/tests/uk_contract_row_scenarios.py b/tests/uk_contract_row_scenarios.py
new file mode 100644
index 00000000..ae1593a7
--- /dev/null
+++ b/tests/uk_contract_row_scenarios.py
@@ -0,0 +1,103 @@
+"""Report rows from ``evaluate_case`` over fixed fake routes.
+
+``test_uk_budget_reform_contract.py`` compares these rows, without their
+``assertion_id``, with rows recorded from the runner before assertion ids
+existed (``fixtures/uk_contract/evaluate_case_rows.json``), so labelling the
+rows cannot change any verdict, expected value or actual value. To record the
+fixture again from a given runner:
+
+    python tests/uk_contract_row_scenarios.py tests/fixtures/uk_contract/evaluate_case_rows.json
+"""
+
+import hashlib
+import json
+import sys
+
+
+class _Values(dict):
+    """A route's values: any requested key gets a fixed, key-specific value."""
+
+    def __init__(self, value):
+        super().__init__()
+        self._value = value
+
+    def __missing__(self, key):
+        return self._value(key)
+
+
+def _hashed(key, salt: str) -> float:
+    digest = hashlib.sha256(repr((salt, *key)).encode()).digest()
+    return round(int.from_bytes(digest[:4], "big") / 2**32 * 1000, 6)
+
+
+def _flat(key) -> float:
+    return 0.20 if key[0] == "parameter" else 1000.0
+
+
+#: The row fields that make up a verdict: which check, its status, and the
+#: values compared.
+VERDICT_FIELDS = (
+    "case_id",
+    "route",
+    "check",
+    "status",
+    "expected",
+    "actual",
+    "decision_id",
+    "holds",
+)
+
+#: name: (reformed values, unreformed values, isolation and after rows, error)
+VARIANTS = {
+    "hashed": (
+        lambda key: _hashed(key, "reformed"),
+        lambda key: _hashed(key, "unreformed"),
+        [("income_tax", 2027, 5.0, 5.0), ("income_tax", 2028, 5.0, 6.0)],
+        None,
+    ),
+    "unchanged": (_flat, _flat, [], None),
+    "error": (None, None, [], RuntimeError("route failed")),
+}
+
+
+def scenario_rows(contract, cases) -> list[dict]:
+    """Rows for every case, route and variant, without assertion ids."""
+
+    saved = contract._route, contract._baseline_parameter_reader
+    rows = []
+    try:
+        contract._baseline_parameter_reader = lambda: lambda path, year: 0.20
+        for variant, (reformed, unreformed, extra, error) in VARIANTS.items():
+
+            class Route:
+                def run(self, case, representation, cache):
+                    if error is not None:
+                        raise error
+                    run = contract.RouteRun()
+                    run.reformed = _Values(reformed)
+                    run.unreformed = _Values(unreformed)
+                    run.isolation.extend(extra)
+                    run.after.extend(extra)
+                    return run
+
+            contract._route = lambda name: Route()
+            for case in cases:
+                for route in contract.ROUTES:
+                    for row in contract.evaluate_case(case, route):
+                        rows.append(
+                            {"variant": variant}
+                            | {key: row.get(key) for key in VERDICT_FIELDS}
+                        )
+    finally:
+        contract._route, contract._baseline_parameter_reader = saved
+    return json.loads(json.dumps(rows, default=str))
+
+
+if __name__ == "__main__":
+    from policyengine.tax_benefit_models.uk import budget_reform_contract as contract
+
+    rows = scenario_rows(contract, contract.CASES)
+    with open(sys.argv[1], "w") as handle:
+        json.dump(rows, handle, sort_keys=True)
+        handle.write("\n")
+    print(len(rows), "rows")

From c19eee4b8fe1a9ecad950453c4a8bd2e52b6e360 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Wed, 14 Oct 2026 08:25:25 -0400
Subject: [PATCH 28/45] Fix round-4 review findings on UK candidate
 qualification

Round-4 review of #574:
- High: the contract gate requires the runner's declared (check, route)
  multiset for population rows, so a deleted route or collapsed coverage
  no longer passes.
- High: assertions have unique ids from the runner; mandatory and pending
  assertions are counted separately and a pending authorization binds only
  to an assertion the runner declares pending.
- Medium: prepare and promote share the promote-uk concurrency group, so
  branch-head replacement and readiness are serialized.
- Medium: baseline metrics install and verify the exact previous certified
  pair (model and core wheels, dataset reference, bytes and manifest); a
  mismatch is incomplete.
- Medium: after qualification receipts are published, failed or timed-out
  pull_request runs for the exact qualified head are re-run with
  gh run rerun --failed (GITHUB_TOKEN, actions: write).
- Medium: staged attempts carry an owner run and a four-hour expiry;
  resolution and catch-up recover an abandoned requestless stage into a
  fresh attempt, keeping prior evidence.

The runner additions the gate relies on (assertion ids and declared
population coverage) are in the previous commit, which is also its own PR
for W1's files.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 .github/workflows/certify-uk-release.yaml     |  60 +-
 scripts/check_uk_candidate.py                 | 141 ++++-
 src/policyengine/provenance/qualification.py  |   4 +
 src/policyengine/provenance/uk_candidate.py   | 545 ++++++++++++++--
 .../provenance/uk_qualification.py            | 167 ++++-
 tests/test_uk_candidate_gates.py              | 204 +++++-
 tests/test_uk_candidate_metric_baselines.py   | 593 ++++++++++++++++++
 tests/test_uk_qualification_pipeline.py       | 343 ++++++++++
 tests/test_uk_qualification_workflow.py       | 331 ++++++++++
 9 files changed, 2314 insertions(+), 74 deletions(-)
 create mode 100644 tests/test_uk_qualification_workflow.py

diff --git a/.github/workflows/certify-uk-release.yaml b/.github/workflows/certify-uk-release.yaml
index 3c13b969..d48946d9 100644
--- a/.github/workflows/certify-uk-release.yaml
+++ b/.github/workflows/certify-uk-release.yaml
@@ -57,6 +57,9 @@ jobs:
     if: github.event_name != 'workflow_dispatch' || inputs.accept_pair_id == ''
     runs-on: ubuntu-latest
     timeout-minutes: 20
+    permissions:
+      contents: read
+      actions: read
     outputs:
       action: ${{ steps.resolve.outputs.action }}
       pair_id: ${{ steps.resolve.outputs.pair_id }}
@@ -81,6 +84,7 @@ jobs:
       - name: Resolve and deduplicate the candidate
         id: resolve
         env:
+          GH_TOKEN: ${{ github.token }}
           HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
           EVENT_NAME: ${{ github.event_name }}
           EVENT_TYPE: ${{ github.event.action }}
@@ -112,7 +116,9 @@ jobs:
     runs-on: ubuntu-latest
     timeout-minutes: 60
     concurrency:
-      group: uk-candidate-${{ needs.resolve.outputs.pair_id }}
+      # Head replacement and readiness must hold the same lock. Otherwise
+      # promotion can ready a replacement after checking the previous head.
+      group: promote-uk
       cancel-in-progress: false
     outputs:
       candidate_commit: ${{ steps.stage.outputs.candidate_commit }}
@@ -130,7 +136,7 @@ jobs:
           token: ${{ steps.app-token.outputs.token }}
           fetch-depth: 0
       # Another run may have staged this attempt while this one waited for
-      # the pair's concurrency group; never overwrite its evidence.
+      # the promotion concurrency group; never overwrite its evidence.
       - name: Check for an attempt staged by another run
         id: duplicate
         env:
@@ -286,6 +292,10 @@ jobs:
     if: always() && needs.prepare.result == 'success' && needs.prepare.outputs.duplicate == 'false'
     runs-on: ubuntu-latest
     timeout-minutes: 355
+    permissions:
+      contents: write
+      pull-requests: write
+      actions: write
     steps:
       - uses: actions/checkout@v6
         with:
@@ -319,6 +329,10 @@ jobs:
           python scripts/check_uk_candidate.py finalize --attempt "$ATTEMPT" --ledger ledger --pr-body "$RUNNER_TEMP/pr-body.md"
           .github/qualification-ledger.sh publish ledger \
             "Qualification receipt for UK candidate ${{ needs.resolve.outputs.pair_id }}"
+      - name: Refresh failed candidate PR checks against the published receipt
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: python scripts/check_uk_candidate.py refresh-pr-checks --ledger ledger
       - name: Generate GitHub App token
         id: app-token
         uses: actions/create-github-app-token@v1
@@ -335,6 +349,10 @@ jobs:
     if: github.event_name == 'schedule'
     runs-on: ubuntu-latest
     timeout-minutes: 30
+    permissions:
+      contents: write
+      pull-requests: write
+      actions: write
     steps:
       - uses: actions/checkout@v6
         with:
@@ -348,11 +366,35 @@ jobs:
           python-version: ${{ env.PYTHON_VERSION }}
       - name: Install policyengine without country models
         run: uv pip install --system -e .
-      - name: Finish attempts whose replay outlasted their run
+      - name: Restart abandoned attempts without replay requests
         env:
           GH_TOKEN: ${{ github.token }}
         run: |
           .github/qualification-ledger.sh checkout ledger
+          python scripts/check_uk_candidate.py recoverable --ledger ledger > recoverable.jsonl
+          python - <<'PY'
+          import json
+          import os
+          import subprocess
+          from pathlib import Path
+
+          for line in Path("recoverable.jsonl").read_text().splitlines():
+              pair = json.loads(line)["pair"]
+              subprocess.run(
+                  [
+                      "gh", "workflow", "run", "certify-uk-release.yaml",
+                      "--repo", os.environ["GITHUB_REPOSITORY"], "--ref", "main",
+                      "-f", f"model_version={pair['model']['version']}",
+                      "-f", f"data_version={pair['data']['release_version']}",
+                      "-f", "force=false",
+                  ],
+                  check=True,
+              )
+          PY
+      - name: Finish attempts whose replay outlasted their run
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: |
           python scripts/check_uk_candidate.py waiting --ledger ledger > waiting.txt
           while read -r attempt; do
             [[ -z "$attempt" ]] && continue
@@ -360,11 +402,19 @@ jobs:
             python scripts/check_uk_candidate.py finalize --attempt "$attempt" --ledger ledger
           done < waiting.txt
           .github/qualification-ledger.sh publish ledger "Catch up waiting UK replay receipts"
+      - name: Refresh failed candidate PR checks against the published receipts
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: python scripts/check_uk_candidate.py refresh-pr-checks --ledger ledger
 
   accept:
     if: github.event_name == 'workflow_dispatch' && inputs.accept_pair_id != ''
     runs-on: ubuntu-latest
     timeout-minutes: 15
+    permissions:
+      contents: write
+      pull-requests: write
+      actions: write
     steps:
       - uses: actions/checkout@v6
         with:
@@ -390,6 +440,10 @@ jobs:
             --pair-id "$PAIR_ID" --receipt-sha256 "$RECEIPT" \
             --explanation "$EXPLANATION" --reviewer "$REVIEWER"
           .github/qualification-ledger.sh publish ledger "Accept UK candidate $PAIR_ID on review by $REVIEWER"
+      - name: Refresh failed candidate PR checks against the accepted receipt
+        env:
+          GH_TOKEN: ${{ github.token }}
+        run: python scripts/check_uk_candidate.py refresh-pr-checks --ledger ledger
 
   promote:
     needs: [resolve, replay, catch-up, accept]
diff --git a/scripts/check_uk_candidate.py b/scripts/check_uk_candidate.py
index 59a281fc..9a5ac8eb 100644
--- a/scripts/check_uk_candidate.py
+++ b/scripts/check_uk_candidate.py
@@ -16,6 +16,7 @@
     python scripts/check_uk_candidate.py poll-replay --attempt  [--wait-minutes 340]
     python scripts/check_uk_candidate.py finalize --attempt  --ledger ledger/
     python scripts/check_uk_candidate.py waiting --ledger ledger/
+    python scripts/check_uk_candidate.py refresh-pr-checks --ledger ledger/
     python scripts/check_uk_candidate.py promote --ledger ledger/ [--apply]
     python scripts/check_uk_candidate.py accept --ledger ledger/ --pair-id ... \\
         --receipt-sha256 ... --explanation "..." [--reviewer login]
@@ -33,6 +34,7 @@
 import subprocess
 import sys
 import time
+from functools import lru_cache
 from pathlib import Path
 from typing import Any, Optional
 
@@ -62,8 +64,10 @@
     ResolvedCandidate,
     WheelFile,
     accept_review,
+    attempt_is_recoverable,
     attempt_is_waiting_for_replay,
     attempt_key,
+    attempt_supersedes_receipt,
     build_replay_request,
     candidate_action,
     candidate_branch,
@@ -212,18 +216,23 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         data_version=args.data_version or None,
     )
     base_commit = git("rev-parse", "HEAD")
+    resolved_at = utc_now()
     action, reason = candidate_action(
         resolved.pair,
         bundle,
         Path(args.ledger) if args.ledger else None,
         base_commit=base_commit,
         force=args.force,
+        now=resolved_at,
+        owner_is_failed=owner_run_failed,
     )
     key = attempt_key(
         resolved.pair,
         Path(args.ledger) if args.ledger else None,
         base_commit=base_commit,
         force=args.force,
+        now=resolved_at,
+        owner_is_failed=owner_run_failed,
     )
     payload = {
         "pair": resolved.pair.canonical_payload(),
@@ -239,6 +248,16 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         "reason": reason,
         "previous_certificate": previous_certificate(bundle).canonical_payload(),
     }
+    if action == "qualify" and args.ledger:
+        published = (
+            pair_directory(Path(args.ledger), "uk", resolved.pair.pair_id)
+            / "qualification_receipt.json"
+        )
+        if published.exists():
+            receipt = QualificationReceipt.model_validate(read_json(published))
+            if receipt.verdict != "incomplete":
+                # Forced work, or recovery of work already bound to this receipt.
+                payload["supersedes_receipt_sha256"] = receipt.unreviewed_sha256
     write_json(Path(args.out), payload)
     print(
         f"{action}: {reason} (pair {resolved.pair.pair_id[:12]}, {resolved.pair.order_key})"
@@ -278,7 +297,13 @@ def cmd_stage(args: argparse.Namespace) -> int:
     attempt = attempt_directory(
         Path(args.ledger), "uk", payload["pair_id"], payload["attempt_key"]
     )
-    stage_attempt(attempt, payload, harness)
+    stage_attempt(
+        attempt,
+        payload,
+        harness,
+        owner_run_id=os.environ.get("GITHUB_RUN_ID"),
+        staged_at=utc_now(),
+    )
     print(f"staged {attempt} at {harness.git_commit}")
     set_output(attempt=str(attempt), candidate_commit=harness.git_commit)
     return 0
@@ -411,6 +436,60 @@ def cmd_waiting(args: argparse.Namespace) -> int:
     return 0
 
 
+@lru_cache(maxsize=256)
+def owner_run_failed(run_id: str) -> bool:
+    """Only a confirmed failed terminal run relinquishes its unexpired stage."""
+
+    result = subprocess.run(
+        [
+            "gh",
+            "run",
+            "view",
+            run_id,
+            "--repo",
+            LEDGER_REPOSITORY,
+            "--json",
+            "status,conclusion",
+        ],
+        text=True,
+        capture_output=True,
+        check=False,
+    )
+    if result.returncode:
+        return False
+    try:
+        state = json.loads(result.stdout)
+    except json.JSONDecodeError:
+        return False
+    return state.get("status") == "completed" and state.get("conclusion") in {
+        "failure",
+        "cancelled",
+        "timed_out",
+        "startup_failure",
+        "action_required",
+        "stale",
+    }
+
+
+def cmd_recoverable(args: argparse.Namespace) -> int:
+    now = utc_now()
+    for pair_dir in sorted((Path(args.ledger) / "uk").glob("*")):
+        receipt = pair_dir / "qualification_receipt.json"
+        stages = list((pair_dir / "attempts").glob("*/staging.json"))
+        if not stages:
+            continue
+        attempt = max(stages, key=lambda path: int(read_json(path)["sequence"])).parent
+        if receipt.exists():
+            terminal = QualificationReceipt.model_validate(read_json(receipt))
+            if terminal.verdict != "incomplete" and not attempt_supersedes_receipt(
+                attempt, terminal
+            ):
+                continue
+        if attempt_is_recoverable(attempt, now=now, owner_is_failed=owner_run_failed):
+            print(json.dumps(read_json(attempt / "candidate.json")))
+    return 0
+
+
 def _open_candidate_branches() -> dict[str, str]:
     """Open candidate branches and the commit each one's pull request is at."""
 
@@ -435,6 +514,58 @@ def _open_candidate_branches() -> dict[str, str]:
     return {item["headRefName"]: item["headRefOid"] for item in json.loads(listing)}
 
 
+def cmd_refresh_pr_checks(args: argparse.Namespace) -> int:
+    """Re-evaluate failed PR checks now that their exact receipt is published.
+
+    The PR workflow does not subscribe to edits or ready_for_review events.
+    GITHUB_TOKEN may re-run existing failed runs with actions: write.
+    """
+
+    branches = _open_candidate_branches()
+    for receipt in latest_receipts(Path(args.ledger)):
+        branch = candidate_branch(receipt.pair)
+        head = receipt.harness.git_commit
+        if not receipt.promotable or branches.get(branch) != head:
+            continue
+        listing = subprocess.run(
+            [
+                "gh",
+                "api",
+                f"repos/{LEDGER_REPOSITORY}/actions/runs"
+                f"?head_sha={head}&event=pull_request&per_page=100",
+                "--paginate",
+                "--jq",
+                ".workflow_runs[] | {id, head_sha, event, status, conclusion} | tojson",
+            ],
+            check=True,
+            capture_output=True,
+            text=True,
+        ).stdout
+        for line in listing.splitlines():
+            run = json.loads(line)
+            if (
+                run["head_sha"] != head
+                or run["event"] != "pull_request"
+                or run["status"] != "completed"
+                or run["conclusion"] not in {"failure", "timed_out"}
+            ):
+                continue
+            subprocess.run(
+                [
+                    "gh",
+                    "run",
+                    "rerun",
+                    str(run["id"]),
+                    "--repo",
+                    LEDGER_REPOSITORY,
+                    "--failed",
+                ],
+                check=True,
+            )
+            print(f"Re-running failed PR checks in run {run['id']} at {head}")
+    return 0
+
+
 def cmd_promote(args: argparse.Namespace) -> int:
     bundle = json.loads(BUNDLE_PATH.read_text())
     receipts = latest_receipts(Path(args.ledger))
@@ -564,6 +695,14 @@ def parser() -> argparse.ArgumentParser:
     waiting.add_argument("--ledger", required=True)
     waiting.set_defaults(func=cmd_waiting)
 
+    refresh = commands.add_parser("refresh-pr-checks")
+    refresh.add_argument("--ledger", required=True)
+    refresh.set_defaults(func=cmd_refresh_pr_checks)
+
+    recoverable = commands.add_parser("recoverable")
+    recoverable.add_argument("--ledger", required=True)
+    recoverable.set_defaults(func=cmd_recoverable)
+
     promote = commands.add_parser("promote")
     promote.add_argument("--ledger", required=True)
     promote.add_argument("--apply", action="store_true")
diff --git a/src/policyengine/provenance/qualification.py b/src/policyengine/provenance/qualification.py
index 45a04ccf..90b6085f 100644
--- a/src/policyengine/provenance/qualification.py
+++ b/src/policyengine/provenance/qualification.py
@@ -42,6 +42,7 @@
 )
 
 from policyengine.provenance.canonical import canonical_sha256
+from policyengine.provenance.manifest import ArtifactPathReference
 from policyengine.provenance.receipt import (
     GIT_SHA_PATTERN,
     SHA256_PATTERN,
@@ -222,6 +223,9 @@ class PreviousCertificate(_Contract):
     qualification_pair_id: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
     model_wheel_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
     core_wheel_sha256: Optional[str] = Field(default=None, pattern=SHA256_PATTERN)
+    dataset_reference: Optional[ArtifactPathReference] = None
+    dataset_name: Optional[str] = None
+    release_manifest_reference: Optional[ArtifactPathReference] = None
 
 
 class ReplayReference(_Contract):
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 16ddb053..255b9a00 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -644,7 +644,7 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
             )
         ]
         checks: list[tuple[str, str, Optional[str]]] = []
-        pending: dict[tuple[str, str, Optional[str]], str] = {}
+        assertions: dict[tuple[str, str, str, str], dict[str, Any]] = {}
         unsupported = getattr(module, "UNSUPPORTED_ROUTES", {})
         country_routes = set(
             getattr(
@@ -665,15 +665,18 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
                 elif getattr(case, "expect_error", None) is not None:
                     checks.append((str(case.id), str(route), "rejected"))
                 else:
-                    for check in getattr(case, "checks", ()):
+                    for index, check in enumerate(getattr(case, "checks", ())):
                         key = (
                             str(case.id),
                             str(route),
                             f"{check.target}:{check.name}:{check.year}",
                         )
                         checks.append(key)
-                        if getattr(check, "pending", None) is not None:
-                            pending[key] = str(check.pending)
+                        assertion_id = f"{key[2]}:{index}"
+                        assertions[(*key, assertion_id)] = {
+                            "oracle": getattr(check, "oracle", None),
+                            "pending": getattr(check, "pending", None),
+                        }
                         # evaluate_case declares these per-check exemptions;
                         # route-wide exemptions above replace the entire case.
                         if check.target == "parameter" and route not in country_routes:
@@ -746,7 +749,7 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
                     ("baseline_isolation:", "unreformed_after_reform:")
                 )
             },
-            "pending_checks": pending,
+            "assertions": assertions,
             "pending_decisions": {
                 str(decision) for decision in getattr(module, "PENDING_DECISIONS", ())
             },
@@ -757,30 +760,86 @@ def _contract_coverage(module: Any) -> Optional[dict[str, Any]]:
                 if any(route not in unsupported for route in routes)
                 else []
             ),
-            "population": getattr(module, "POPULATION_CHECKS", None),
+            "population": getattr(module, "POPULATION_CHECK_ROUTES", None),
         }
     except AttributeError:
         return None
 
 
 def _declared_population_checks(
-    module_name: str, importer: Callable[[str], Any]
-) -> list[str]:
-    """Population check IDs documented by W1's population runner itself.
-
-    W1 currently exposes no machine-readable per-route population coverage
-    matrix. Its module docstring declares the checks by ID, which supports
-    requiring every declared check, but not inventing route counts. Prefer
-    an explicit declaration if the runner adds one.
-    """
+    module_name: str, importer: Callable[[str], Any], routes: Sequence[str]
+) -> list[tuple[str, str]]:
+    """The runner's complete population check/route multiset."""
 
     module = importer(module_name.rsplit(".", 1)[0] + ".budget_reform_population")
-    declared = getattr(module, "POPULATION_CHECKS", None)
+    declared = getattr(module, "POPULATION_CHECK_ROUTES", None)
     if declared is not None:
-        return [str(check) for check in declared]
-    return re.findall(
+        return [(str(check), str(route)) for check, route in declared]
+    coverage = getattr(module, "population_check_routes", None)
+    if callable(coverage):
+        return [(str(check), str(route)) for check, route in coverage(routes)]
+    # IDs alone cannot prove that every route ran. Retain their names in the
+    # diagnostic, while refusing a runner with no per-route declaration.
+    ids = getattr(module, "POPULATION_CHECKS", None) or re.findall(
         r"^``([a-z][a-z0-9_]+)``$", inspect.getdoc(module) or "", re.MULTILINE
     )
+    raise AttributeError(
+        "the population runner declares no population check routes"
+        + (": " + ", ".join(str(check) for check in ids) if ids else "")
+    )
+
+
+def _reported_assertions(
+    rows: Sequence[Mapping[str, Any]], coverage: Mapping[str, Any]
+) -> tuple[dict[int, tuple[str, str, str, str]], list[str]]:
+    """Resolve current assertion IDs and unambiguous historical oracle rows.
+
+    Released reports predate assertion IDs. Their oracles distinguish checks
+    with the same label. Whole-route exemptions have no values or oracles;
+    their interchangeable rows are consumed in declaration order instead.
+    """
+    resolved = {}
+    problems = []
+    used: Counter[tuple[str, str, str, str]] = Counter()
+    by_label: dict[tuple[str, str, str], list[tuple[str, str, str, str]]] = {}
+    for key in coverage["assertions"]:
+        by_label.setdefault(key[:3], []).append(key)
+    for row in rows:
+        label = (str(row.get("case_id")), str(row.get("route")), row.get("check"))
+        matches = list(by_label.get(label, ()))
+        if not matches:
+            continue  # Isolation, run-level and rejected-case rows are separate.
+        assertion_id = row.get("assertion_id")
+        if assertion_id is not None:
+            matches = [key for key in matches if key[3] == assertion_id]
+            if row.get("oracle") is not None:
+                matches = [
+                    key
+                    for key in matches
+                    if coverage["assertions"][key]["oracle"] == row["oracle"]
+                ]
+        elif len(matches) > 1:
+            if row.get("oracle") is not None:
+                matches = [
+                    key
+                    for key in matches
+                    if coverage["assertions"][key]["oracle"] == row["oracle"]
+                ]
+            elif (
+                row.get("status") == "unsupported"
+                and label in coverage["unsupported_checks"]
+            ):
+                matches = [key for key in matches if not used[key]][:1]
+            else:
+                matches = []
+        if len(matches) != 1:
+            problems.append(
+                f"case {label[0]}@{label[1]}:{label[2]} has no unique declared assertion identity"
+            )
+            continue
+        resolved[id(row)] = matches[0]
+        used[matches[0]] += 1
+    return resolved, problems
 
 
 #: Report sections: the key that names each row, and what a row is called.
@@ -859,6 +918,12 @@ def reform_contract(
     unsupported: list[str] = []
     counts = dict.fromkeys(_CONTRACT_STATUSES, 0)
     coverage = _contract_coverage(runner_module)
+    reported_assertions = {}
+    if coverage is not None:
+        reported_assertions, assertion_problems = _reported_assertions(
+            report.get("cases") or [], coverage
+        )
+        malformed.extend(assertion_problems)
     population_exemptions = {}
     population_module = None
     if dataset_path is not None:
@@ -890,13 +955,9 @@ def reform_contract(
             elif status == "pending":
                 decision = row.get("decision_id")
                 declared_decision = (
-                    coverage["pending_checks"].get(
-                        (
-                            str(row.get("case_id")),
-                            str(row.get("route")),
-                            row.get("check"),
-                        )
-                    )
+                    coverage["assertions"]
+                    .get(reported_assertions.get(id(row)), {})
+                    .get("pending")
                     if coverage and section == "cases"
                     else None
                 )
@@ -904,8 +965,20 @@ def reform_contract(
                     malformed.append(
                         f"{label} did not run: properties cannot be pending"
                     )
+                elif section == "population":
+                    malformed.append(
+                        f"{label} is a mandatory assertion: population checks cannot be pending"
+                    )
                 elif not decision:
                     malformed.append(f"{label} is pending without a decision_id")
+                elif section == "cases" and declared_decision is None:
+                    malformed.append(
+                        f"{label} is a mandatory assertion relabelled pending"
+                    )
+                elif section == "cases" and decision != declared_decision:
+                    malformed.append(
+                        f"{label} is pending for undeclared decision {decision}"
+                    )
                 elif decision != declared_decision and decision not in allowed_pending:
                     malformed.append(
                         f"{label} is pending for undeclared decision {decision}"
@@ -1013,6 +1086,43 @@ def reform_contract(
                     for case, route, check in list(absent_checks)[:4]
                 )
             )
+        # A pending decision belongs to one declared assertion. Count each
+        # assertion separately and never let pending rows satisfy mandatory
+        # rows, even where the runner reads the same parameter twice.
+        for category in ("mandatory", "pending"):
+            expected = Counter(
+                key
+                for key, declaration in coverage["assertions"].items()
+                if key[:2] not in crashed
+                and (
+                    "pending"
+                    if declaration["pending"] is not None
+                    and key[:3] not in coverage["unsupported_checks"]
+                    else "mandatory"
+                )
+                == category
+            )
+            actual = Counter(
+                reported_assertions[id(row)]
+                for row in report.get("cases") or []
+                if id(row) in reported_assertions
+                and ("pending" if row.get("status") == "pending" else "mandatory")
+                == category
+            )
+            absent_assertions = expected - actual
+            excess_assertions = actual - expected
+            if absent_assertions or excess_assertions:
+                malformed.append(
+                    f"{category} assertion multiplicities differ: "
+                    f"{sum(absent_assertions.values())} missing, "
+                    f"{sum(excess_assertions.values())} extra; "
+                    + ", ".join(
+                        f"{case}@{route}:{assertion_id}"
+                        for case, route, _, assertion_id in list(
+                            absent_assertions or excess_assertions
+                        )[:4]
+                    )
+                )
         for case, route in coverage["run_pairs"]:
             rows = [
                 row
@@ -1060,23 +1170,34 @@ def reform_contract(
                         else entrypoint.rpartition(".")[0]
                     )
                     declared_population = _declared_population_checks(
-                        module_name, importer
+                        module_name, importer, coverage["routes"]
                     )
-                except (ImportError, AttributeError):
+                except (ImportError, AttributeError) as exc:
+                    malformed.append(str(exc))
                     declared_population = []
             if not declared_population:
                 malformed.append(
                     "the runner declares no population checks, so population coverage cannot be checked"
                 )
             else:
-                population = {
-                    str(row.get("check_id")) for row in report.get("population") or []
-                }
-                absent_population = sorted(set(declared_population) - population)
-                if absent_population:
+                population = Counter(
+                    (str(row.get("check_id")), str(row.get("route")))
+                    for row in report.get("population") or []
+                )
+                expected_population = Counter(declared_population)
+                absent_population = expected_population - population
+                excess_population = population - expected_population
+                if absent_population or excess_population:
                     malformed.append(
-                        "declared population check(s) have no row: "
-                        + ", ".join(absent_population)
+                        "declared population check route multiplicities differ: "
+                        f"{sum(absent_population.values())} missing, "
+                        f"{sum(excess_population.values())} extra; "
+                        + ", ".join(
+                            f"{check}@{route}"
+                            for check, route in list(
+                                absent_population or excess_population
+                            )
+                        )
                     )
         properties = {
             str(row.get("property_id")): row for row in report.get("properties") or []
@@ -1871,18 +1992,179 @@ def run_metrics_report(
     return report
 
 
-def previous_pair_python(
+class PreviousPairUnavailable(ValueError):
+    """The exact certified baseline cannot be constructed or verified."""
+
+
+def _previous_pair_pins(
+    previous: Mapping[str, Any], ledger_root: Optional[Path] = None
+) -> dict[str, Any]:
+    """Certificate pins, completed by its exact ledger receipt when available."""
+
+    pins = dict(previous)
+    pair_id = previous.get("qualification_pair_id")
+    if ledger_root is not None and pair_id:
+        try:
+            receipt = QualificationReceipt.model_validate_json(
+                (
+                    ledger_root / "uk" / pair_id / "qualification_receipt.json"
+                ).read_text()
+            )
+        except (OSError, ValueError) as exc:
+            raise PreviousPairUnavailable(
+                "The previous pair's ledger receipt is unavailable."
+            ) from exc
+        pair = receipt.pair
+        expected = {
+            "model_version": pair.model.version,
+            "core_version": pair.core.version,
+            "data_release_version": pair.data.release_version,
+            "dataset_sha256": pair.data.dataset_sha256,
+            "model_wheel_sha256": pair.model.wheel_sha256,
+            "core_wheel_sha256": pair.core.wheel_sha256,
+        }
+        if (
+            not receipt.promotable
+            or receipt.pair_id != pair_id
+            or any(
+                previous.get(key) is not None and previous[key] != value
+                for key, value in expected.items()
+            )
+        ):
+            raise PreviousPairUnavailable(
+                "The previous certificate and ledger name different pairs."
+            )
+        reference = {
+            "repo_id": pair.data.repo_id,
+            "repo_type": pair.data.repo_type,
+            "path": pair.data.dataset_path,
+            "revision": pair.data.dataset_revision,
+            "sha256": pair.data.dataset_sha256,
+        }
+        recorded_reference = previous.get("dataset_reference")
+        if recorded_reference and any(
+            recorded_reference.get(key) != value for key, value in reference.items()
+        ):
+            raise PreviousPairUnavailable(
+                "The previous dataset reference differs from its ledger pair."
+            )
+        pins.update(
+            expected,
+            dataset_reference=reference,
+            dataset_name=pair.data.dataset,
+            release_manifest_reference={
+                "repo_id": pair.data.repo_id,
+                "repo_type": pair.data.repo_type,
+                "path": pair.data.release_manifest_path,
+                "revision": pair.data.release_manifest_revision,
+                "sha256": pair.data.release_manifest_sha256,
+            },
+        )
+    for key in (
+        "bundle_version",
+        "model_version",
+        "core_version",
+        "data_release_version",
+        "dataset_sha256",
+    ):
+        if not isinstance(pins.get(key), str) or not pins[key]:
+            raise PreviousPairUnavailable(f"The previous certificate has no {key} pin.")
+    reference = pins.get("dataset_reference")
+    if (
+        not isinstance(reference, Mapping)
+        or any(
+            not isinstance(reference.get(key), str) or not reference[key]
+            for key in ("repo_id", "path", "revision")
+        )
+        or reference.get("repo_type") not in ("model", "dataset")
+        or reference.get("sha256") != pins["dataset_sha256"]
+        or not re.fullmatch(r"[a-f0-9]{64}", pins["dataset_sha256"])
+    ):
+        raise PreviousPairUnavailable(
+            "The previous certificate has no exact dataset reference."
+        )
+    return pins
+
+
+# This verification subprocess uses the current verifier, independently of
+# whether the older published wrapper included it. Its namespace is isolated
+# from the later metrics subprocess, which uses the installed previous wrapper.
+PREVIOUS_IDENTITY_RUNNER = """
+import importlib.metadata as metadata, json, sys, types
+from pathlib import Path
+settings, out = json.loads(sys.argv[1]), Path(sys.argv[2])
+package = types.ModuleType("policyengine")
+package.__path__ = [settings["source"]]
+sys.modules["policyengine"] = package
+from policyengine.provenance.wheels import verify_installed_against_wheel
+problems = []
+for wheel in settings["wheels"]:
+    name = wheel["name"]
+    try:
+        if metadata.version(name) != wheel["version"]:
+            problems.append(name + ": installed version differs from the previous certificate")
+        evidence = verify_installed_against_wheel(name, Path(wheel["path"]))
+        if evidence["wheel_sha256"] != wheel["sha256"]:
+            problems.append(name + ": wheel hash differs from the previous certificate")
+        problems.extend(evidence["problems"])
+    except (metadata.PackageNotFoundError, OSError, ValueError) as exc:
+        problems.append(name + ": cannot verify installation: " + str(exc))
+out.write_text(json.dumps({"problems": problems}))
+"""
+
+
+def _construct_previous_pair_python(
     previous: Mapping[str, Any],
     work_dir: Path,
     *,
+    ledger_root: Optional[Path] = None,
     run: Optional[Callable[..., Any]] = None,
 ) -> str:
-    """A throwaway venv with the previous certified release installed."""
+    """Install and verify the certificate's wheels, independently of wrapper extras."""
 
     import subprocess
 
+    import requests
+
+    from policyengine.provenance.uk_qualification import _wheel
+
     run = run if run is not None else subprocess.run
-    venv = work_dir / f"previous-{previous['bundle_version']}"
+    pins = _previous_pair_pins(previous, ledger_root)
+    wheels = []
+    for name, kind in (("policyengine-uk", "model"), ("policyengine-core", "core")):
+        version = pins[f"{kind}_version"]
+        response = requests.get(
+            f"https://pypi.org/pypi/{name}/{version}/json", timeout=30
+        )
+        response.raise_for_status()
+        wheel = _wheel(response.json()["urls"], name, version)
+        expected_sha256 = pins.get(f"{kind}_wheel_sha256") or wheel.sha256
+        if wheel.sha256 != expected_sha256:
+            raise PreviousPairUnavailable(
+                f"{name}: PyPI wheel differs from the previous certificate."
+            )
+        path = _download(
+            wheel.url,
+            work_dir / "previous-wheels" / expected_sha256 / wheel.filename,
+            get=requests.get,
+        )
+        if sha256_file(path) != expected_sha256:
+            raise PreviousPairUnavailable(
+                f"{name}: downloaded wheel differs from the previous certificate."
+            )
+        wheels.append(
+            {
+                "name": name,
+                "version": version,
+                "sha256": expected_sha256,
+                "path": str(path),
+            }
+        )
+    # Same wrapper version can certify several pairs during its publication window.
+    # The environment cache must include the resolved wheel and dataset pins.
+    venv = (
+        work_dir / f"previous-{content_sha256({'pins': pins, 'wheels': wheels})[:24]}"
+    )
     python = venv / "bin" / "python"
     if not python.exists():
         run(["uv", "venv", str(venv), "--python", "3.13"], check=True)
@@ -1893,13 +2175,176 @@ def previous_pair_python(
                 "install",
                 "--python",
                 str(python),
-                f"policyengine[uk]=={previous['bundle_version']}",
+                f"policyengine=={pins['bundle_version']}",
+                *(wheel["path"] for wheel in wheels),
             ],
             check=True,
         )
+    output = work_dir / "previous-identity.json"
+    output.unlink(missing_ok=True)
+    run(
+        [
+            str(python),
+            "-c",
+            PREVIOUS_IDENTITY_RUNNER,
+            json.dumps(
+                {
+                    "source": str(Path(__file__).resolve().parents[1]),
+                    "wheels": wheels,
+                }
+            ),
+            str(output),
+        ],
+        check=True,
+    )
+    identity = json.loads(output.read_text())
+    if not isinstance(identity, Mapping) or identity.get("problems") != []:
+        raise PreviousPairUnavailable(
+            f"The installed previous pair does not match its pins: {identity}."
+        )
     return str(python)
 
 
+def _materialize_previous_pair_dataset(
+    previous: Mapping[str, Any], work_dir: Path, *, ledger_root: Optional[Path] = None
+) -> Path:
+    """Materialize the previous certificate's exact data, bypassing wrapper defaults."""
+
+    import os
+
+    import requests
+
+    pins = _previous_pair_pins(previous, ledger_root)
+    reference = pins["dataset_reference"]
+    path = (
+        work_dir
+        / "previous-data"
+        / pins["dataset_sha256"]
+        / Path(reference["path"]).name
+    )
+    if not path.exists():
+        token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN")
+        url = _hf_url(
+            reference["repo_id"],
+            reference["repo_type"],
+            reference["revision"],
+            reference["path"],
+        )
+        _download(
+            url,
+            path,
+            get=lambda *args, **kwargs: requests.get(
+                *args,
+                **kwargs,
+                headers={"Authorization": f"Bearer {token}"} if token else {},
+            ),
+        )
+    if sha256_file(path) != pins["dataset_sha256"]:
+        raise PreviousPairUnavailable(
+            "The previous dataset bytes differ from the certificate."
+        )
+    manifest_reference = pins.get("release_manifest_reference") or {}
+    if (
+        any(
+            not isinstance(manifest_reference.get(key), str)
+            or not manifest_reference[key]
+            for key in ("repo_id", "path", "revision")
+        )
+        or manifest_reference.get("repo_type") not in ("model", "dataset")
+        or not pins.get("dataset_name")
+    ):
+        raise PreviousPairUnavailable(
+            "The previous data release has no pinned manifest reference."
+        )
+    token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN")
+    response = requests.get(
+        _hf_url(
+            manifest_reference["repo_id"],
+            manifest_reference["repo_type"],
+            manifest_reference["revision"],
+            manifest_reference["path"],
+        ),
+        headers={"Authorization": f"Bearer {token}"} if token else {},
+        timeout=30,
+    )
+    response.raise_for_status()
+    if (
+        manifest_reference.get("sha256")
+        and hashlib.sha256(response.content).hexdigest() != manifest_reference["sha256"]
+    ):
+        raise PreviousPairUnavailable(
+            "The previous release manifest bytes differ from the ledger."
+        )
+    manifest = DataReleaseManifest.model_validate_json(response.content)
+    artifact = manifest.artifacts.get(pins["dataset_name"])
+    if (
+        manifest.data_package.version != pins["data_release_version"]
+        or manifest.default_datasets.get("national") != pins["dataset_name"]
+        or artifact is None
+        or artifact.sha256 != pins["dataset_sha256"]
+        or artifact.path != reference["path"]
+        or artifact.revision != reference["revision"]
+        or artifact.repo_id != reference["repo_id"]
+        or (artifact.repo_type or manifest_reference["repo_type"])
+        != reference["repo_type"]
+    ):
+        raise PreviousPairUnavailable(
+            "The previous release manifest does not match the certified data pair."
+        )
+    return path
+
+
+def previous_pair_python(
+    previous: Mapping[str, Any],
+    work_dir: Path,
+    *,
+    ledger_root: Optional[Path] = None,
+    run: Optional[Callable[..., Any]] = None,
+) -> str:
+    """Construct a verified baseline, or report that it is unavailable."""
+
+    import subprocess
+
+    import requests
+
+    try:
+        return _construct_previous_pair_python(
+            previous, work_dir, ledger_root=ledger_root, run=run
+        )
+    except PreviousPairUnavailable:
+        raise
+    except (
+        OSError,
+        ValueError,
+        KeyError,
+        TypeError,
+        subprocess.CalledProcessError,
+        requests.RequestException,
+    ) as exc:
+        raise PreviousPairUnavailable(
+            f"The exact previous environment could not be verified: {exc}"
+        ) from exc
+
+
+def previous_pair_dataset(
+    previous: Mapping[str, Any], work_dir: Path, *, ledger_root: Optional[Path] = None
+) -> Path:
+    """Materialize verified previous data, or report that it is unavailable."""
+
+    import requests
+
+    try:
+        return _materialize_previous_pair_dataset(
+            previous, work_dir, ledger_root=ledger_root
+        )
+    except PreviousPairUnavailable:
+        raise
+    except (OSError, ValueError, KeyError, TypeError, requests.RequestException) as exc:
+        raise PreviousPairUnavailable(
+            f"The exact previous data could not be verified: {exc}"
+        ) from exc
+
+
 # --- Orchestration -------------------------------------------------------------
 
 
@@ -1908,6 +2353,10 @@ def run_gate(gate_id: str, function: Callable[[], GateOutcome]) -> GateOutcome:
 
     try:
         return function()
+    except PreviousPairUnavailable as exc:
+        return _result(
+            gate_id, "unavailable", str(exc), {"previous_pair_unavailable": str(exc)}
+        )
     except Exception as exc:
         return _result(
             gate_id,
@@ -2118,6 +2567,16 @@ def gate_data_access() -> GateOutcome:
             state["manifest"] = manifest
         return result, evidence
 
+    def previous_environment() -> tuple[str, Path]:
+        if "previous_environment" not in state:
+            assert previous_certificate is not None
+            pins = _previous_pair_pins(previous_certificate, ledger_root)
+            state["previous_environment"] = (
+                previous_pair_python(pins, work_dir),
+                previous_pair_dataset(pins, work_dir),
+            )
+        return state["previous_environment"]
+
     def previous_snapshot() -> Optional[dict[str, Any]]:
         """The previous pair's inputs and years: from the ledger, else computed."""
 
@@ -2135,11 +2594,12 @@ def previous_snapshot() -> Optional[dict[str, Any]]:
                 "source": "ledger",
             }
         elif previous_certificate:
+            previous_python, previous_dataset = previous_environment()
             snapshot = run_inputs_snapshot(
-                previous_pair_python(previous_certificate, work_dir),
+                previous_python,
                 critical=critical_spec["critical"],
                 out=work_dir / "previous-inputs.json",
-                data_dir=work_dir / "previous-data",
+                dataset_path=previous_dataset,
             )
             snapshot["source"] = (
                 f"computed with policyengine {previous_certificate['bundle_version']}"
@@ -2275,15 +2735,16 @@ def gate_metrics() -> GateOutcome:
                 unavailable_reason="No previous certificate to compare against.",
             )
         bounds = json.loads((qualification_dir / settings["bounds"]).read_text())
+        previous_python, previous_dataset = previous_environment()
         vendor_root = metrics_tool()
         years = settings["years"]
         candidate_report = candidate_metrics()
         previous_report = run_metrics_report(
-            previous_pair_python(previous_certificate, work_dir),
+            previous_python,
             vendor_root,
             years=years,
             out=work_dir / "metrics-previous.json",
-            data_dir=work_dir / "previous-data",
+            dataset_path=previous_dataset,
             label="previous",
         )
         cross_report = None
diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index 7dd5870a..39965c33 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -40,6 +40,7 @@
 import subprocess
 from collections.abc import Callable, Iterable, Mapping, Sequence
 from dataclasses import dataclass, field
+from datetime import UTC, datetime, timedelta
 from pathlib import Path
 from typing import Any, Literal, Optional
 
@@ -330,6 +331,8 @@ def certified_order_key(bundle: Mapping[str, Any]) -> tuple[str, str, str]:
 
 def previous_certificate(bundle: Mapping[str, Any]) -> PreviousCertificate:
     record = bundle["data_releases"]["uk"]
+    reference = record["datasets"][record["default_dataset"]]
+    data_package = record["data_package"]
     return PreviousCertificate(
         bundle_version=bundle["policyengine_version"],
         model_version=record["model_package"]["version"],
@@ -342,6 +345,19 @@ def previous_certificate(bundle: Mapping[str, Any]) -> PreviousCertificate:
         ),
         model_wheel_sha256=record["model_package"].get("sha256"),
         core_wheel_sha256=bundle["packages"][CORE_PACKAGE].get("sha256"),
+        dataset_reference={
+            **reference,
+            "repo_id": reference.get("repo_id") or data_package["repo_id"],
+            "repo_type": reference.get("repo_type")
+            or data_package.get("repo_type", "model"),
+        },
+        dataset_name=record["default_dataset"],
+        release_manifest_reference={
+            "repo_id": data_package["repo_id"],
+            "repo_type": data_package.get("repo_type", "model"),
+            "path": data_package["release_manifest_path"],
+            "revision": data_package["release_manifest_revision"],
+        },
     )
 
 
@@ -352,6 +368,8 @@ def candidate_action(
     *,
     base_commit: str,
     force: bool = False,
+    now: Optional[str] = None,
+    owner_is_failed: Optional[Callable[[str], bool]] = None,
 ) -> tuple[Action, str]:
     """Whether to qualify ``pair`` now, and why."""
 
@@ -367,12 +385,25 @@ def candidate_action(
         return "qualify", "forced" if force else "no ledger"
     pair_dir = pair_directory(ledger_root, "uk", pair.pair_id)
     latest = pair_dir / "qualification_receipt.json"
-    if latest.exists():
-        receipt = QualificationReceipt.model_validate(read_json(latest))
-        if receipt.verdict != "incomplete":
-            return "duplicate", f"pair already {receipt.verdict} in the ledger"
-    attempt = attempt_directory(ledger_root, "uk", pair.pair_id, base_commit[:12])
-    if attempt.exists():
+    receipt = (
+        QualificationReceipt.model_validate(read_json(latest))
+        if latest.exists()
+        else None
+    )
+    attempt = _latest_base_attempt(pair, ledger_root, base_commit)
+    if (
+        attempt is not None
+        and attempt_is_recoverable(attempt, now=now, owner_is_failed=owner_is_failed)
+        and (
+            receipt is None
+            or receipt.verdict == "incomplete"
+            or attempt_supersedes_receipt(attempt, receipt)
+        )
+    ):
+        return "qualify", "recoverable abandoned staged attempt"
+    if receipt is not None and receipt.verdict != "incomplete":
+        return "duplicate", f"pair already {receipt.verdict} in the ledger"
+    if attempt is not None:
         return "duplicate", f"an attempt from base {base_commit[:12]} exists"
     return "qualify", "new pair, or an incomplete pair on a new base commit"
 
@@ -462,17 +493,24 @@ def attempt_key(
     *,
     base_commit: str,
     force: bool = False,
+    now: Optional[str] = None,
+    owner_is_failed: Optional[Callable[[str], bool]] = None,
 ) -> str:
     """The ledger key of the attempt a qualification run would stage.
 
-    One attempt per base commit, so concurrent runs for the same pair and
-    base deduplicate. A forced run after such an attempt gets the next free
-    key instead, so it stages a fresh attempt and is not mistaken for the
-    old one.
+    Concurrent runs for the same pair and base deduplicate. Forced runs and
+    recovery of abandoned stages use the next free key, preserving earlier
+    evidence. A live replacement blocks further recovery on that base.
     """
 
     key = base_commit[:12]
-    if not force or ledger_root is None:
+    if ledger_root is None:
+        return key
+    attempt = _latest_base_attempt(pair, ledger_root, base_commit)
+    recovering = attempt is not None and attempt_is_recoverable(
+        attempt, now=now, owner_is_failed=owner_is_failed
+    )
+    if not force and not recovering:
         return key
     if not attempt_directory(ledger_root, "uk", pair.pair_id, key).exists():
         return key
@@ -484,6 +522,26 @@ def attempt_key(
     return f"{key}-{repeat}"
 
 
+def _latest_base_attempt(
+    pair: CandidatePair, ledger_root: Path, base_commit: str
+) -> Optional[Path]:
+    base = base_commit[:12]
+    parent = pair_directory(ledger_root, "uk", pair.pair_id) / "attempts"
+    attempts = [
+        path
+        for path in parent.glob(f"{base}*")
+        if path.is_dir() and re.fullmatch(re.escape(base) + r"(?:-\d+)?", path.name)
+    ]
+
+    def order(path: Path) -> tuple[int, int]:
+        stage = path / "staging.json"
+        sequence = int(read_json(stage)["sequence"]) if stage.exists() else 0
+        repeat = int(path.name[len(base) + 1 :]) if path.name != base else 1
+        return sequence, repeat
+
+    return max(attempts, key=order, default=None)
+
+
 def changelog_fragment(pair: CandidatePair, basis_note: str) -> str:
     return (
         f"Certify uk-data {pair.data.release_version} (`{pair.data.dataset}`) with "
@@ -836,6 +894,9 @@ def stage_attempt(
     attempt_dir: Path,
     candidate_payload: Mapping[str, Any],
     harness: QualificationHarness,
+    *,
+    owner_run_id: Optional[str] = None,
+    staged_at: Optional[str] = None,
 ) -> None:
     payloads = {
         attempt_dir / "candidate.json": dict(candidate_payload),
@@ -853,7 +914,30 @@ def stage_attempt(
             int(read_json(path)["sequence"])
             for path in attempt_dir.parent.glob("*/staging.json")
         ]
-        write_json(staging_path, {"sequence": max(prior_orders, default=0) + 1})
+        staged = _attempt_time(staged_at)
+        stage = {
+            "sequence": max(prior_orders, default=0) + 1,
+            "owner_run_id": owner_run_id,
+            "staged_at": staged.isoformat().replace("+00:00", "Z"),
+            "expires_at": (staged + timedelta(hours=4))
+            .isoformat()
+            .replace("+00:00", "Z"),
+        }
+        supersedes = candidate_payload.get("supersedes_receipt_sha256")
+        if supersedes:
+            published = attempt_dir.parent.parent / "qualification_receipt.json"
+            if (
+                not published.exists()
+                or QualificationReceipt.model_validate(
+                    read_json(published)
+                ).unreviewed_sha256
+                != supersedes
+            ):
+                raise ValueError(
+                    "Recovery must bind the exact receipt the forced attempt supersedes"
+                )
+            stage["supersedes_receipt_sha256"] = supersedes
+        write_json(staging_path, stage)
     for path, payload in payloads.items():
         if not path.exists():
             write_json(path, payload)
@@ -1034,6 +1118,65 @@ def attempt_is_waiting_for_replay(attempt_dir: Path) -> bool:
     return GateResult.model_validate(read_json(result)).status == "unavailable"
 
 
+def _attempt_time(value: Optional[str]) -> datetime:
+    instant = (
+        datetime.fromisoformat(value.replace("Z", "+00:00"))
+        if value
+        else datetime.now(UTC)
+    )
+    if instant.tzinfo is None:
+        raise ValueError("Attempt timestamps must have a timezone")
+    return instant.astimezone(UTC)
+
+
+def attempt_is_recoverable(
+    attempt_dir: Path,
+    *,
+    now: Optional[str] = None,
+    owner_is_failed: Optional[Callable[[str], bool]] = None,
+) -> bool:
+    """An abandoned stage can be retried in a new immutable attempt directory.
+
+    Sent requests retain the replay catch-up path. A live owner retains its
+    stage until expiry; unknown GitHub status never implies owner failure.
+    Older stages without ownership metadata are recoverable as unowned work.
+    """
+
+    if (attempt_dir / "replay" / "request.json").exists():
+        return False
+    receipt_path = attempt_dir / "qualification_receipt.json"
+    if (
+        receipt_path.exists()
+        and QualificationReceipt.model_validate(read_json(receipt_path)).verdict
+        != "incomplete"
+    ):
+        return False
+    stage_path = attempt_dir / "staging.json"
+    if not stage_path.exists() or not (attempt_dir / "candidate.json").exists():
+        return False
+    stage = read_json(stage_path)
+    expires = stage.get("expires_at")
+    if expires and _attempt_time(now) >= _attempt_time(expires):
+        return True
+    owner = stage.get("owner_run_id")
+    if owner and owner_is_failed is not None and owner_is_failed(str(owner)):
+        return True
+    return not owner and not expires
+
+
+def attempt_supersedes_receipt(
+    attempt_dir: Path, receipt: QualificationReceipt
+) -> bool:
+    """Only explicitly authorized newer work may supersede a terminal receipt."""
+
+    stage = attempt_dir / "staging.json"
+    return (
+        stage.exists()
+        and read_json(stage).get("supersedes_receipt_sha256")
+        == receipt.unreviewed_sha256
+    )
+
+
 # --- Promotion ----------------------------------------------------------------
 
 
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index c051d536..6ddedd3b 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -550,11 +550,12 @@ def _declared_coverage(source):
     source = source or {}
     from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
 
-    declared_checks = {
-        (case.id, check.target, check.name, check.year): check
-        for case in runner.CASES
-        for check in case.checks
-    }
+    declared_checks = {}
+    for case in runner.CASES:
+        for check in case.checks:
+            declared_checks.setdefault(
+                (case.id, check.target, check.name, check.year), []
+            ).append(check)
     by_case = {}
     for row in source.get("cases") or []:
         by_case.setdefault(row.get("case_id"), []).append(row)
@@ -569,14 +570,11 @@ def _declared_coverage(source):
                         target=label.split(":")[0],
                         name=label.split(":")[1],
                         year=int(label.split(":")[2]),
-                        expected=getattr(
-                            declared_checks.get(
-                                (case, *label.split(":")[:2], int(label.split(":")[2]))
-                            ),
-                            "expected",
-                            None,
-                        ),
-                        pending=next(
+                        expected=getattr(declaration, "expected", None),
+                        oracle=getattr(declaration, "oracle", None),
+                        pending=getattr(declaration, "pending", None)
+                        if declaration
+                        else next(
                             (
                                 row.get("decision_id")
                                 for row in rows
@@ -590,6 +588,10 @@ def _declared_coverage(source):
                     and len(label.split(":")) == 3
                     and label.split(":")[0]
                     not in ("baseline_isolation", "unreformed_after_reform")
+                    for declaration in declared_checks.get(
+                        (case, *label.split(":")[:2], int(label.split(":")[2])),
+                        [None],
+                    )
                 ),
                 expect_error="rejected"
                 if any(row.get("check") == "rejected" for row in rows)
@@ -617,8 +619,8 @@ def _declared_coverage(source):
             for row in source.get("cases") or []
             if row.get("decision_id")
         },
-        "POPULATION_CHECKS": tuple(
-            dict.fromkeys(row["check_id"] for row in source.get("population") or [])
+        "POPULATION_CHECK_ROUTES": tuple(
+            (row["check_id"], row["route"]) for row in source.get("population") or []
         ),
     }
 
@@ -723,9 +725,16 @@ def _run_level_row():
                         {
                             "case_id": "freeze",
                             "route": "wrapper.policy",
+                            "check": "variable:income_tax:2027",
                             "status": "pending",
                             "decision_id": "d1344",
                         },
+                        {
+                            "case_id": "freeze",
+                            "route": "wrapper.policy",
+                            "check": "unreformed_after_reform:income_tax:2027",
+                            "status": "pass",
+                        },
                         _run_level_row(),
                     ]
                 }
@@ -889,6 +898,141 @@ def test_population_cannot_exempt_every_required_check():
     )
 
 
+@pytest.mark.parametrize("row_index", range(19))
+def test_each_population_route_row_is_required(row_index):
+    report = _fixture("full_released_uk_2.126.12.json")
+    omitted = report["population"].pop(row_index)
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any(
+        f"{omitted['check_id']}@{omitted['route']}" in problem
+        for problem in result.details["problems"]
+    )
+
+
+def test_deleting_a_failed_uc_population_route_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    omitted = next(
+        row
+        for row in report["population"]
+        if row["check_id"] == "population_uc_standard_allowance_plus_10"
+        and row["route"] == "country.scenario_parameter_changes"
+    )
+    omitted["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    report["population"].remove(omitted)
+    assert _run_released_contract(_recount(report)).status == "error"
+
+
+@pytest.mark.parametrize("override", [(), ("d1344",)])
+@pytest.mark.parametrize(
+    "check_id",
+    [
+        "population_query_order",
+        "population_uc_standard_allowance_plus_10",
+        "population_state_pension_plus_10",
+    ],
+)
+def test_population_assertion_cannot_borrow_a_case_pending_decision(override, check_id):
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(row for row in report["population"] if row["check_id"] == check_id)
+    row["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    row.update(status="pending", decision_id="d1344")
+    result = _run_released_contract(_recount(report), pending_decisions=override)
+    assert result.status == "error", result.summary
+    assert any(
+        "population checks cannot be pending" in p for p in result.details["problems"]
+    )
+
+
+def test_one_population_row_per_check_id_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    report["population"] = list(
+        {row["check_id"]: row for row in report["population"]}.values()
+    )
+    assert len(report["population"]) == 7
+    assert _run_released_contract(_recount(report)).status == "error"
+
+
+def test_duplicate_population_route_cannot_replace_another_route():
+    report = _fixture("full_released_uk_2.126.12.json")
+    report["population"][1] = dict(report["population"][0])
+    assert _run_released_contract(_recount(report)).status == "error"
+
+
+def test_an_unknown_assertion_identity_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report["cases"]
+        if row["status"] == "pass" and row.get("oracle") == "frozen"
+    )
+    row["assertion_id"] = "an assertion the runner does not declare"
+    result = _run_released_contract(report)
+    assert result.status == "error", result.summary
+    assert any(
+        "no unique declared assertion identity" in p for p in result.details["problems"]
+    )
+
+
+@pytest.mark.parametrize("override", [(), ("d1344",)])
+def test_mandatory_freeze_assertion_cannot_borrow_pending_authorization(override):
+    report = _fixture("full_released_uk_2.126.12.json")
+    row = next(
+        row
+        for row in report["cases"]
+        if row["case_id"] == "extended_freeze"
+        and row["route"] == "country.reform_dict"
+        and row.get("oracle") == "contract 1.0.0: prior law's projected path resumes"
+    )
+    row["status"] = "fail"
+    assert _run_released_contract(_recount(report)).status == "fail"
+    row.update(status="pending", decision_id="d1344")
+    result = _run_released_contract(_recount(report), pending_decisions=override)
+    assert result.status == "error", result.summary
+    assert any("mandatory assertion" in p for p in result.details["problems"])
+
+
+def test_swapping_mandatory_and_pending_freeze_statuses_cannot_qualify():
+    report = _fixture("full_released_uk_2.126.12.json")
+    rows = [
+        row
+        for row in report["cases"]
+        if row["case_id"] == "extended_freeze"
+        and row["route"] == "country.reform_dict"
+        and row.get("check")
+        == "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034"
+    ]
+    assert len(rows) == 2
+    mandatory = next(row for row in rows if row["status"] == "pass")
+    pending = next(row for row in rows if row["status"] == "pending")
+    mandatory.update(status="pending", decision_id="d1344")
+    pending.update(status="pass", decision_id=None)
+    assert _run_released_contract(_recount(report)).status == "error"
+
+
+@pytest.mark.parametrize("replace_status", ["pass", "pending"])
+def test_duplicate_freeze_assertion_cannot_satisfy_the_other_category(replace_status):
+    report = _fixture("full_released_uk_2.126.12.json")
+    matching = [
+        row
+        for row in report["cases"]
+        if row["case_id"] == "extended_freeze"
+        and row["route"] == "country.reform_dict"
+        and row.get("check")
+        == "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034"
+    ]
+    source = next(row for row in matching if row["status"] == replace_status)
+    replaced = next(row for row in matching if row["status"] != replace_status)
+    report["cases"][report["cases"].index(replaced)] = dict(source)
+    result = _run_released_contract(_recount(report))
+    assert result.status == "error", result.summary
+    assert any(
+        "assertion multiplicities differ" in p for p in result.details["problems"]
+    )
+
+
 @pytest.mark.parametrize("route", ["api.sim_api", "wrapper.household"])
 def test_declared_case_exemptions_require_the_runners_reason(route):
     report = _fixture("full_released_uk_2.126.12.json")
@@ -1107,7 +1251,7 @@ def test_population_coverage_uses_the_population_runners_declarations():
     report = _passing_report()
     importer = _importer(report=report, coverage=report)
     module = importer("contract")
-    del module.POPULATION_CHECKS
+    del module.POPULATION_CHECK_ROUTES
     population = SimpleNamespace()
     population.__doc__ = (
         "Checks:\n\n``new_population_check``\n    Declared by the population runner."
@@ -1125,6 +1269,31 @@ def test_population_coverage_uses_the_population_runners_declarations():
     assert "new_population_check" in result.summary
 
 
+def test_new_population_route_declaration_is_required_without_a_gate_side_list(
+    monkeypatch,
+):
+    from policyengine.tax_benefit_models.uk import (
+        budget_reform_population as population,
+    )
+
+    declared = population.population_check_routes
+    monkeypatch.setattr(
+        population,
+        "population_check_routes",
+        lambda routes: (*declared(routes), ("new_population_check", "unreformed")),
+    )
+    report = _fixture("full_released_uk_2.126.12.json")
+    result = _run_released_contract(report)
+    assert result.status == "error", result.summary
+    assert any(
+        "new_population_check@unreformed" in p for p in result.details["problems"]
+    )
+    report["population"].append(
+        {"check_id": "new_population_check", "route": "unreformed", "status": "pass"}
+    )
+    assert _run_released_contract(_recount(report)).status == "pass"
+
+
 REPORT_TAMPERING = {
     "invented pending decision": lambda r: _recount(
         {
@@ -1655,6 +1824,9 @@ def snapshot(*args, **kwargs):
     monkeypatch.setattr(gates_module, "vendor_metrics_tool", lambda *a, **k: tmp_path)
     monkeypatch.setattr(gates_module, "load_standard_reforms", lambda *a: [])
     monkeypatch.setattr(gates_module, "previous_pair_python", lambda *a: "python")
+    monkeypatch.setattr(
+        gates_module, "previous_pair_dataset", lambda *a: tmp_path / "dataset.h5"
+    )
     monkeypatch.setattr(
         gates_module,
         "run_metrics_report",
diff --git a/tests/test_uk_candidate_metric_baselines.py b/tests/test_uk_candidate_metric_baselines.py
index 712a65a6..38f087e4 100644
--- a/tests/test_uk_candidate_metric_baselines.py
+++ b/tests/test_uk_candidate_metric_baselines.py
@@ -108,3 +108,596 @@ def test_valid_baselines_preserve_bounds_and_do_not_mutate_reports():
     status, _, evidence = compare_metric_reports(candidate, previous, BOUNDS)
     assert status == "needs_review"
     assert evidence["moves_beyond_bounds"][0]["metric_id"] == "income_tax"
+
+
+def _previous_certificate():
+    return {
+        "bundle_version": "6.3.0",
+        "model_version": "2.125.1",
+        "core_version": "3.33.0",
+        "model_wheel_sha256": "1" * 64,
+        "core_wheel_sha256": "2" * 64,
+        "data_release_version": "1.58.0",
+        "dataset_sha256": "3" * 64,
+        "dataset_name": "national",
+        "release_manifest_reference": {
+            "repo_id": "policyengine/uk-data",
+            "repo_type": "model",
+            "path": "releases/1.58.0/release_manifest.json",
+            "revision": "b" * 40,
+        },
+        "dataset_reference": {
+            "repo_id": "policyengine/uk-data",
+            "repo_type": "model",
+            "path": "national.h5",
+            "revision": "a" * 40,
+            "sha256": "3" * 64,
+        },
+    }
+
+
+def _previous_install_io(
+    tmp_path, monkeypatch, *, bad_pypi=None, bad_download=None, identity_problems=None
+):
+    import json
+    from pathlib import Path
+    from types import SimpleNamespace
+
+    import requests
+
+    from policyengine.provenance import uk_candidate
+
+    previous = _previous_certificate()
+    commands = []
+
+    def get(url, **kwargs):
+        package, version = url.removeprefix("https://pypi.org/pypi/").split("/")[:2]
+        digest = previous[
+            "model_wheel_sha256"
+            if package == "policyengine-uk"
+            else "core_wheel_sha256"
+        ]
+        if package == bad_pypi:
+            digest = "0" * 64
+        return SimpleNamespace(
+            raise_for_status=lambda: None,
+            json=lambda: {
+                "urls": [
+                    {
+                        "packagetype": "bdist_wheel",
+                        "filename": f"{package.replace('-', '_')}-{version}-py3-none-any.whl",
+                        "url": f"https://wheels/{package}/{version}",
+                        "digests": {"sha256": digest},
+                    }
+                ]
+            },
+        )
+
+    def run(command, **kwargs):
+        commands.append(command)
+        if command[:2] == ["uv", "venv"]:
+            python = Path(command[2]) / "bin/python"
+            python.parent.mkdir(parents=True)
+            python.touch()
+        elif "-c" in command:
+            Path(command[-1]).write_text(
+                json.dumps({"problems": identity_problems or []})
+            )
+
+    monkeypatch.setattr(requests, "get", get)
+    monkeypatch.setattr(uk_candidate, "_download", lambda url, path, **kwargs: path)
+    monkeypatch.setattr(
+        uk_candidate,
+        "sha256_file",
+        lambda path: (
+            "0" * 64
+            if (
+                ("policyengine_uk" in path.name and bad_download == "policyengine-uk")
+                or (
+                    "policyengine_core" in path.name
+                    and bad_download == "policyengine-core"
+                )
+            )
+            else previous[
+                "model_wheel_sha256"
+                if "policyengine_uk" in path.name
+                else "core_wheel_sha256"
+            ]
+        ),
+    )
+    return previous, commands, run
+
+
+def test_previous_baseline_installs_the_certificate_pair_not_the_wrapper_extra(
+    tmp_path, monkeypatch
+):
+    from policyengine.provenance import uk_candidate
+
+    previous, commands, run = _previous_install_io(tmp_path, monkeypatch)
+    uk_candidate.previous_pair_python(previous, tmp_path, run=run)
+    install = next(
+        command for command in commands if command[:3] == ["uv", "pip", "install"]
+    )
+    assert f"policyengine=={previous['bundle_version']}" in install
+    assert not any(argument.startswith("policyengine[uk]") for argument in install)
+    assert any("policyengine_uk-2.125.1" in argument for argument in install)
+    assert any("policyengine_core-3.33.0" in argument for argument in install)
+    assert any("-c" in command for command in commands), (
+        "The installed wheels must be verified."
+    )
+
+
+@pytest.mark.parametrize("package", ["policyengine-uk", "policyengine-core"])
+@pytest.mark.parametrize("source", ["PyPI", "download"])
+def test_previous_baseline_refuses_a_different_wheel_hash(
+    tmp_path, monkeypatch, package, source
+):
+    from policyengine.provenance import uk_candidate
+
+    previous, _, run = _previous_install_io(
+        tmp_path,
+        monkeypatch,
+        bad_pypi=package if source == "PyPI" else None,
+        bad_download=package if source == "download" else None,
+    )
+    result, _ = uk_candidate.run_gate(
+        "metrics_review",
+        lambda: uk_candidate.previous_pair_python(previous, tmp_path, run=run),
+    )
+    assert result.status == "unavailable"
+    assert package in result.summary and "wheel differs" in result.summary
+
+
+def test_previous_baseline_refuses_installed_mismatches_and_rechecks_reused_environments(
+    tmp_path, monkeypatch
+):
+    from policyengine.provenance import uk_candidate
+
+    previous, commands, run = _previous_install_io(tmp_path, monkeypatch)
+    first = uk_candidate.previous_pair_python(previous, tmp_path, run=run)
+    second = uk_candidate.previous_pair_python(previous, tmp_path, run=run)
+    assert first == second
+    assert sum(command[:2] == ["uv", "venv"] for command in commands) == 1
+    assert sum("-c" in command for command in commands) == 2
+    previous, _, run = _previous_install_io(
+        tmp_path,
+        monkeypatch,
+        identity_problems=["policyengine-core: installed bytes differ"],
+    )
+    result, _ = uk_candidate.run_gate(
+        "metrics_review",
+        lambda: uk_candidate.previous_pair_python(previous, tmp_path, run=run),
+    )
+    assert result.status == "unavailable"
+    assert "installed bytes differ" in result.summary
+
+
+def test_previous_baseline_cache_changes_when_same_wrapper_certifies_a_new_pair(
+    tmp_path, monkeypatch
+):
+    from policyengine.provenance import uk_candidate
+
+    previous, _, run = _previous_install_io(tmp_path, monkeypatch)
+    first = uk_candidate.previous_pair_python(previous, tmp_path, run=run)
+    previous["model_version"] = "2.126.12"
+    second = uk_candidate.previous_pair_python(previous, tmp_path, run=run)
+    assert first != second
+
+
+@pytest.mark.parametrize(
+    "changed_pin",
+    [
+        "model_version",
+        "core_version",
+        "data_release_version",
+        "dataset_sha256",
+        "model_wheel_sha256",
+        "core_wheel_sha256",
+    ],
+)
+def test_a_ledger_baseline_must_match_every_previous_certificate_pin(
+    tmp_path, changed_pin
+):
+    from policyengine.provenance import uk_candidate
+    from policyengine.provenance.qualification_ledger import write_json
+    from tests.qualification_fixtures import make_pair, make_receipt
+
+    pair = make_pair()
+    previous = {
+        "bundle_version": "6.3.0",
+        "qualification_pair_id": pair.pair_id,
+        "model_version": pair.model.version,
+        "core_version": pair.core.version,
+        "data_release_version": pair.data.release_version,
+        "dataset_sha256": pair.data.dataset_sha256,
+    }
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        make_receipt(pair).canonical_payload(),
+    )
+    previous[changed_pin] = "0" * 64 if changed_pin.endswith("sha256") else "999.0.0"
+    result, _ = uk_candidate.run_gate(
+        "metrics_review", lambda: uk_candidate._previous_pair_pins(previous, tmp_path)
+    )
+    assert result.status == "unavailable"
+    assert "different pairs" in result.summary
+
+
+def test_a_ledger_baseline_supplies_exact_wheel_and_data_pins(tmp_path):
+    from policyengine.provenance import uk_candidate
+    from policyengine.provenance.qualification_ledger import write_json
+    from tests.qualification_fixtures import make_pair, make_receipt
+
+    pair = make_pair()
+    previous = {
+        "bundle_version": "6.3.0",
+        "qualification_pair_id": pair.pair_id,
+        "model_version": pair.model.version,
+        "core_version": pair.core.version,
+        "data_release_version": pair.data.release_version,
+        "dataset_sha256": pair.data.dataset_sha256,
+    }
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        make_receipt(pair).canonical_payload(),
+    )
+    pins = uk_candidate._previous_pair_pins(previous, tmp_path)
+    assert pins["model_wheel_sha256"] == pair.model.wheel_sha256
+    assert pins["core_wheel_sha256"] == pair.core.wheel_sha256
+    assert pins["dataset_reference"] == {
+        "repo_id": pair.data.repo_id,
+        "repo_type": pair.data.repo_type,
+        "path": pair.data.dataset_path,
+        "revision": pair.data.dataset_revision,
+        "sha256": pair.data.dataset_sha256,
+    }
+
+
+@pytest.mark.parametrize("package", ["policyengine-uk", "policyengine-core"])
+@pytest.mark.parametrize(
+    "mismatch", ["version", "wheel", "installed bytes", "missing package"]
+)
+def test_baseline_identity_verification_detects_installed_mismatches(
+    tmp_path, monkeypatch, package, mismatch
+):
+    import json
+    import sys
+
+    from policyengine.provenance import uk_candidate, wheels
+
+    settings = {
+        "source": str(
+            __import__("pathlib").Path(uk_candidate.__file__).resolve().parents[1]
+        ),
+        "wheels": [
+            {
+                "name": name,
+                "version": "1.0.0",
+                "sha256": "1" * 64,
+                "path": str(tmp_path / f"{name}.whl"),
+            }
+            for name in ("policyengine-uk", "policyengine-core")
+        ],
+    }
+
+    def installed_version(name):
+        from importlib.metadata import PackageNotFoundError
+
+        if name == package and mismatch == "missing package":
+            raise PackageNotFoundError(name)
+        return "2.0.0" if name == package and mismatch == "version" else "1.0.0"
+
+    monkeypatch.setattr("importlib.metadata.version", installed_version)
+    monkeypatch.setattr(
+        wheels,
+        "verify_installed_against_wheel",
+        lambda name, path: {
+            "wheel_sha256": "2" * 64
+            if name == package and mismatch == "wheel"
+            else "1" * 64,
+            "problems": [f"{name}: mutated installed bytes"]
+            if name == package and mismatch == "installed bytes"
+            else [],
+        },
+    )
+    output = tmp_path / "identity.json"
+    monkeypatch.setattr(sys, "argv", ["runner", json.dumps(settings), str(output)])
+    # Restore the package namespace the isolated verifier creates when the test ends.
+    monkeypatch.setitem(sys.modules, "policyengine", sys.modules["policyengine"])
+    exec(
+        compile(uk_candidate.PREVIOUS_IDENTITY_RUNNER, "previous-identity", "exec"), {}
+    )
+    report = json.loads(output.read_text())
+    assert report["problems"] and package in report["problems"][0]
+
+
+def test_previous_data_is_downloaded_from_its_pin_and_verified(tmp_path, monkeypatch):
+    import hashlib
+    import json
+    from types import SimpleNamespace
+
+    import requests
+
+    from policyengine.provenance import uk_candidate
+
+    data = b"exact previous data"
+    digest = hashlib.sha256(data).hexdigest()
+    previous = _previous_certificate()
+    previous["dataset_sha256"] = previous["dataset_reference"]["sha256"] = digest
+    urls = []
+
+    def download(url, path, **kwargs):
+        urls.append(url)
+        path.parent.mkdir(parents=True)
+        path.write_bytes(data)
+        return path
+
+    monkeypatch.setattr(uk_candidate, "_download", download)
+    monkeypatch.setattr(
+        requests,
+        "get",
+        lambda *args, **kwargs: SimpleNamespace(
+            raise_for_status=lambda: None,
+            content=json.dumps(_previous_release_manifest(previous)).encode(),
+        ),
+    )
+    path = uk_candidate.previous_pair_dataset(previous, tmp_path)
+    assert urls == [
+        "https://huggingface.co/policyengine/uk-data/resolve/"
+        + "a" * 40
+        + "/national.h5"
+    ]
+    assert path.read_bytes() == data
+    path.write_bytes(b"wrong published wrapper data")
+    result, _ = uk_candidate.run_gate(
+        "metrics_review", lambda: uk_candidate.previous_pair_dataset(previous, tmp_path)
+    )
+    assert result.status == "unavailable"
+    assert "dataset bytes differ" in result.summary
+
+
+def _previous_release_manifest(previous):
+    return {
+        "schema_version": 1,
+        "country_id": "uk",
+        "data_package": {
+            "name": "uk-data",
+            "version": previous["data_release_version"],
+        },
+        "default_datasets": {"national": previous["dataset_name"]},
+        "artifacts": {
+            previous["dataset_name"]: {
+                "kind": "microdata",
+                **previous["dataset_reference"],
+            }
+        },
+    }
+
+
+@pytest.mark.parametrize(
+    "mismatch",
+    [
+        "release",
+        "default dataset",
+        "dataset sha",
+        "dataset revision",
+        "dataset path",
+        "dataset repo",
+        "dataset repo type",
+        "dataset absent",
+        "manifest sha",
+    ],
+)
+def test_previous_baseline_refuses_a_mismatched_release_manifest(
+    tmp_path, monkeypatch, mismatch
+):
+    import hashlib
+    import json
+    from types import SimpleNamespace
+
+    import requests
+
+    from policyengine.provenance import uk_candidate
+
+    previous = _previous_certificate()
+    data = b"certified previous data"
+    digest = hashlib.sha256(data).hexdigest()
+    previous["dataset_sha256"] = previous["dataset_reference"]["sha256"] = digest
+    path = tmp_path / "previous-data" / digest / "national.h5"
+    path.parent.mkdir(parents=True)
+    path.write_bytes(data)
+    manifest = _previous_release_manifest(previous)
+    if mismatch == "release":
+        manifest["data_package"]["version"] = "999.0.0"
+    elif mismatch == "default dataset":
+        manifest["default_datasets"]["national"] = "wrong"
+    elif mismatch == "dataset sha":
+        manifest["artifacts"]["national"]["sha256"] = "0" * 64
+    elif mismatch == "dataset revision":
+        manifest["artifacts"]["national"]["revision"] = "c" * 40
+    elif mismatch == "dataset path":
+        manifest["artifacts"]["national"]["path"] = "other.h5"
+    elif mismatch == "dataset repo":
+        manifest["artifacts"]["national"]["repo_id"] = "policyengine/other-data"
+    elif mismatch == "dataset repo type":
+        manifest["artifacts"]["national"]["repo_type"] = "dataset"
+    elif mismatch == "dataset absent":
+        manifest["artifacts"] = {}
+    else:
+        previous["release_manifest_reference"]["sha256"] = "0" * 64
+    monkeypatch.setattr(
+        requests,
+        "get",
+        lambda *a, **k: SimpleNamespace(
+            raise_for_status=lambda: None, content=json.dumps(manifest).encode()
+        ),
+    )
+    result, _ = uk_candidate.run_gate(
+        "metrics_review", lambda: uk_candidate.previous_pair_dataset(previous, tmp_path)
+    )
+    assert result.status == "unavailable"
+    assert "manifest" in result.summary
+
+
+@pytest.mark.parametrize(
+    "missing",
+    ["dataset_reference", "dataset_sha256", "core_version", "data_release_version"],
+)
+def test_unpinned_previous_baselines_are_incomplete(tmp_path, missing):
+    from policyengine.provenance import uk_candidate
+
+    previous = _previous_certificate()
+    del previous[missing]
+    result, _ = uk_candidate.run_gate(
+        "metrics_review", lambda: uk_candidate.previous_pair_dataset(previous, tmp_path)
+    )
+    assert result.status == "unavailable"
+
+
+@pytest.mark.parametrize("identity_mismatch", [False, True])
+def test_metric_orchestration_uses_the_verified_previous_dataset_before_computing(
+    tmp_path, monkeypatch, identity_mismatch
+):
+    import json
+    from pathlib import Path
+    from types import SimpleNamespace
+
+    from policyengine.provenance import dataset_materialization, uk_candidate
+    from tests.qualification_fixtures import HARNESS, make_pair
+
+    previous = _previous_certificate()
+    previous_path = tmp_path / "certified-previous.h5"
+    candidate_path = tmp_path / "candidate.h5"
+    config = json.loads(
+        (
+            Path(__file__).parents[1] / "src/policyengine/data/qualification/uk.json"
+        ).read_text()
+    )
+    calls = []
+    monkeypatch.setattr(uk_candidate, "_previous_pair_pins", lambda *args: previous)
+    monkeypatch.setattr(
+        uk_candidate, "previous_pair_python", lambda *args: "certified-previous-python"
+    )
+
+    def previous_dataset(*args):
+        if identity_mismatch:
+            raise uk_candidate.PreviousPairUnavailable(
+                "Previous dataset identity mismatch"
+            )
+        return previous_path
+
+    monkeypatch.setattr(uk_candidate, "previous_pair_dataset", previous_dataset)
+    monkeypatch.setattr(
+        dataset_materialization,
+        "materialize_dataset",
+        lambda *a, **k: SimpleNamespace(path=candidate_path),
+    )
+    monkeypatch.setattr(uk_candidate, "vendor_metrics_tool", lambda *a, **k: tmp_path)
+
+    def only_metrics(gates):
+        gate = next(function for name, function in gates if name == "metrics_review")
+        result, evidence = uk_candidate.run_gate("metrics_review", gate)
+        return [result], {"metrics_review": evidence}
+
+    monkeypatch.setattr(uk_candidate, "run_gates", only_metrics)
+
+    def metrics(python, vendor, **settings):
+        calls.append((python, settings))
+        report = _report()
+        report["dataset_path"] = str(settings["dataset_path"])
+        if settings["label"] != "previous":
+            report["metrics"][0]["value"] = 1e12
+        return report
+
+    monkeypatch.setattr(uk_candidate, "run_metrics_report", metrics)
+    results, _ = uk_candidate.run_candidate_gates(
+        SimpleNamespace(pair=make_pair()),
+        HARNESS,
+        config=config,
+        work_dir=tmp_path,
+        previous_certificate=previous,
+        ledger_root=None,
+    )
+    if identity_mismatch:
+        assert results[0].status == "unavailable"
+        assert calls == [], (
+            "Unverified baselines must be refused before computing metrics."
+        )
+    else:
+        assert results[0].status == "needs_review"
+        previous_call = next(call for call in calls if call[1]["label"] == "previous")
+        assert previous_call[0] == "certified-previous-python"
+        assert previous_call[1]["dataset_path"] == previous_path
+        assert "data_dir" not in previous_call[1]
+
+
+@pytest.mark.parametrize(
+    "failure", ["install", "verifier", "missing report", "bad json", "bad schema"]
+)
+def test_baseline_installation_or_verification_failure_is_incomplete(
+    tmp_path, monkeypatch, failure
+):
+    import subprocess
+    from pathlib import Path
+
+    from policyengine.provenance import uk_candidate
+
+    previous, _, fake_run = _previous_install_io(tmp_path, monkeypatch)
+
+    def run(command, **kwargs):
+        if (failure == "install" and command[:3] == ["uv", "pip", "install"]) or (
+            failure == "verifier" and "-c" in command
+        ):
+            raise subprocess.CalledProcessError(1, command)
+        fake_run(command, **kwargs)
+        if "-c" in command:
+            output = Path(command[-1])
+            if failure == "missing report":
+                output.unlink()
+            elif failure == "bad json":
+                output.write_text("invalid json")
+            elif failure == "bad schema":
+                output.write_text("[]")
+
+    result, _ = uk_candidate.run_gate(
+        "metrics_review",
+        lambda: uk_candidate.previous_pair_python(previous, tmp_path, run=run),
+    )
+    assert result.status == "unavailable"
+
+
+@pytest.mark.parametrize(
+    "mismatch", ["receipt pair", "receipt verdict", "dataset reference"]
+)
+def test_previous_pair_cannot_borrow_another_ledgers_identity(tmp_path, mismatch):
+    from policyengine.provenance import uk_candidate
+    from policyengine.provenance.qualification_ledger import write_json
+    from tests.qualification_fixtures import gates, make_pair, make_receipt
+
+    pair = make_pair()
+    previous = {
+        "bundle_version": "6.3.0",
+        "qualification_pair_id": pair.pair_id,
+        "model_version": pair.model.version,
+        "core_version": pair.core.version,
+        "data_release_version": pair.data.release_version,
+        "dataset_sha256": pair.data.dataset_sha256,
+    }
+    receipt = make_receipt(pair)
+    if mismatch == "receipt pair":
+        receipt = make_receipt(make_pair(core="3.32.0"))
+        previous["core_version"] = (
+            "3.32.0"  # Other pins match; the receipt's pair id must still match.
+        )
+    elif mismatch == "receipt verdict":
+        receipt = make_receipt(pair, gate_results=gates("fail"))
+    else:
+        previous["dataset_reference"] = {"path": "other.h5"}
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        receipt.canonical_payload(),
+    )
+    result, _ = uk_candidate.run_gate(
+        "metrics_review", lambda: uk_candidate._previous_pair_pins(previous, tmp_path)
+    )
+    assert result.status == "unavailable"
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index 4b212969..8c15ca83 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -773,6 +773,349 @@ def test_the_workflow_drafts_existing_prs_before_replacing_their_head(
 # --- Attempt lifecycle -----------------------------------------------------------------
 
 
+@pytest.mark.parametrize("abandonment", ["expired", "failed_owner"])
+def test_abandoned_stage_recovers_without_reusing_evidence(tmp_path, abandonment):
+    from policyengine.provenance.qualification_ledger import (
+        attempt_directory,
+        read_json,
+    )
+    from policyengine.provenance.uk_qualification import (
+        attempt_is_recoverable,
+        attempt_key,
+        stage_attempt,
+    )
+
+    pair = make_pair(model="2.200.0")
+    base = "a" * 40
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12])
+    payload = {"pair": pair.canonical_payload(), "base_commit": base}
+    stage_attempt(attempt, payload, HARNESS)
+    # The owner fails before request-replay, leaving durable but unfinished work.
+    write_json(
+        attempt / "staging.json",
+        {
+            "sequence": 1,
+            "owner_run_id": "42",
+            "staged_at": "2026-10-14T10:00:00Z",
+            "expires_at": "2026-10-14T14:00:00Z",
+        },
+    )
+    original = read_json(attempt / "candidate.json")
+    now = "2026-10-14T15:00:00Z" if abandonment == "expired" else "2026-10-14T11:00:00Z"
+
+    def failed(run_id):
+        return abandonment == "failed_owner" and run_id == "42"
+
+    assert attempt_is_recoverable(attempt, now=now, owner_is_failed=failed)
+    assert (
+        candidate_action(
+            pair, BUNDLE, tmp_path, base_commit=base, now=now, owner_is_failed=failed
+        )[0]
+        == "qualify"
+    )
+    new_key = attempt_key(
+        pair, tmp_path, base_commit=base, now=now, owner_is_failed=failed
+    )
+    assert new_key == base[:12] + "-2"
+    new_attempt = attempt_directory(tmp_path, "uk", pair.pair_id, new_key)
+    stage_attempt(new_attempt, payload, HARNESS, owner_run_id="43", staged_at=now)
+    assert read_json(attempt / "candidate.json") == original
+    assert (
+        candidate_action(
+            pair, BUNDLE, tmp_path, base_commit=base, now=now, owner_is_failed=failed
+        )[0]
+        == "duplicate"
+    )
+
+
+@pytest.mark.parametrize("protected", ["live", "request", "terminal", "missing_stage"])
+def test_recovery_preserves_live_sent_and_terminal_attempts(tmp_path, protected):
+    from policyengine.provenance.uk_qualification import (
+        attempt_is_recoverable,
+        stage_attempt,
+    )
+
+    pair = make_pair()
+    attempt = tmp_path / "attempt"
+    stage_attempt(attempt, {"pair": pair.canonical_payload()}, HARNESS)
+    write_json(
+        attempt / "staging.json",
+        {
+            "sequence": 1,
+            "owner_run_id": "42",
+            "expires_at": "2026-10-14T14:00:00Z",
+        },
+    )
+    now = "2026-10-14T15:00:00Z"
+    if protected == "live":
+        now = "2026-10-14T11:00:00Z"
+    elif protected == "request":
+        write_json(attempt / "replay" / "request.json", {"sent": True})
+    elif protected == "terminal":
+        write_json(
+            attempt / "qualification_receipt.json", make_receipt().canonical_payload()
+        )
+    else:
+        (attempt / "staging.json").unlink()
+    assert not attempt_is_recoverable(attempt, now=now, owner_is_failed=lambda _: False)
+
+
+def test_stage_records_owner_and_expiry_immutably(tmp_path):
+    from policyengine.provenance.qualification_ledger import read_json
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    payload = {"pair": make_pair().canonical_payload()}
+    stage_attempt(
+        tmp_path, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
+    )
+    stage = read_json(tmp_path / "staging.json")
+    assert stage["owner_run_id"] == "42"
+    assert stage["expires_at"] == "2026-10-14T14:00:00Z"
+    stage_attempt(tmp_path, payload, HARNESS, owner_run_id="43")
+    assert read_json(tmp_path / "staging.json") == stage
+
+
+def test_unowned_legacy_stage_is_recoverable_on_the_same_base(tmp_path):
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    pair = make_pair(model="2.200.0")
+    base = "a" * 40
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12])
+    stage_attempt(attempt, {"pair": pair.canonical_payload()}, HARNESS)
+    write_json(attempt / "staging.json", {"sequence": 1})
+    assert candidate_action(pair, BUNDLE, tmp_path, base_commit=base)[0] == "qualify"
+
+
+def test_newer_abandoned_stage_recovers_despite_an_older_replay_request(tmp_path):
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import attempt_key, stage_attempt
+
+    pair = make_pair(model="2.200.0")
+    base = "a" * 40
+    payload = {"pair": pair.canonical_payload()}
+    earlier = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12])
+    stage_attempt(
+        earlier, payload, HARNESS, owner_run_id="41", staged_at="2026-10-14T09:00:00Z"
+    )
+    write_json(earlier / "replay" / "request.json", {"sent": True})
+    newer = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12] + "-2")
+    stage_attempt(
+        newer, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
+    )
+    now = "2026-10-14T15:00:00Z"
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit=base, now=now)[0]
+        == "qualify"
+    )
+    assert attempt_key(pair, tmp_path, base_commit=base, now=now) == base[:12] + "-3"
+    assert (earlier / "replay" / "request.json").exists()
+
+
+@pytest.mark.parametrize("verdict", ["qualified", "rejected"])
+def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
+    tmp_path, verdict, monkeypatch, capsys
+):
+    import importlib.util
+
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    pair = make_pair(model="2.200.0")
+    results = gates(wheel_hashes="fail") if verdict == "rejected" else gates()
+    terminal = make_receipt(pair=pair, gate_results=results)
+    base = "a" * 40
+    published = tmp_path / "uk" / pair.pair_id / "qualification_receipt.json"
+    write_json(published, terminal.canonical_payload())
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12] + "-2")
+    payload = {
+        "pair": pair.canonical_payload(),
+        "supersedes_receipt_sha256": terminal.unreviewed_sha256,
+    }
+    stage_attempt(
+        attempt, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
+    )
+    now = "2026-10-14T15:00:00Z"
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit=base, now=now)[0]
+        == "qualify"
+    )
+    spec = importlib.util.spec_from_file_location(
+        "check_uk_bound_recovery_for_test", REPO_ROOT / "scripts/check_uk_candidate.py"
+    )
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+    monkeypatch.setattr(cli, "utc_now", lambda: now)
+    assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
+    assert json.loads(capsys.readouterr().out) == payload
+    changed = make_receipt(pair=pair, gate_results=gates(replay="fail"))
+    write_json(published, changed.canonical_payload())
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit=base, now=now)[0]
+        == "duplicate"
+    )
+    with pytest.raises(ValueError, match="exact receipt"):
+        stage_attempt(attempt.parent / (base[:12] + "-3"), payload, HARNESS)
+    assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
+    assert capsys.readouterr().out == ""
+
+
+def test_resolution_preserves_authorization_to_recover_forced_work(
+    tmp_path, monkeypatch
+):
+    import importlib.util
+
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    spec = importlib.util.spec_from_file_location(
+        "check_uk_resolve_recovery_for_test",
+        REPO_ROOT / "scripts/check_uk_candidate.py",
+    )
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+    pair = make_pair(model="2.200.0")
+    terminal = make_receipt(pair=pair, gate_results=gates(replay="fail"))
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        terminal.canonical_payload(),
+    )
+    base = "a" * 40
+    resolved = cli.ResolvedCandidate(
+        pair,
+        cli.WheelFile(
+            "model.whl", "https://example.org/model.whl", pair.model.wheel_sha256
+        ),
+        cli.WheelFile(
+            "core.whl", "https://example.org/core.whl", pair.core.wheel_sha256
+        ),
+        "hf://model/example@pin/manifest.json",
+        ">=3.33.0",
+    )
+    monkeypatch.setattr(cli, "resolve_candidate", lambda **kwargs: resolved)
+    monkeypatch.setattr(cli, "git", lambda *args: base)
+    monkeypatch.setattr(cli, "owner_run_failed", lambda _: False)
+    monkeypatch.setattr(cli, "utc_now", lambda: "2026-10-14T15:00:00Z")
+    monkeypatch.setattr(cli, "set_output", lambda **kwargs: None)
+    out = tmp_path / "candidate.json"
+    args = SimpleNamespace(
+        model_version=None,
+        data_version=None,
+        ledger=str(tmp_path),
+        force=True,
+        out=str(out),
+    )
+    assert cli.cmd_resolve(args) == 0
+    payload = json.loads(out.read_text())
+    assert payload["supersedes_receipt_sha256"] == terminal.unreviewed_sha256
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, payload["attempt_key"])
+    stage_attempt(
+        attempt, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
+    )
+    args.force = False
+    assert cli.cmd_resolve(args) == 0
+    recovery = json.loads(out.read_text())
+    assert recovery["action"] == "qualify"
+    assert recovery["attempt_key"] == base[:12] + "-2"
+    assert recovery["supersedes_receipt_sha256"] == terminal.unreviewed_sha256
+
+
+@pytest.mark.parametrize(
+    ("status", "conclusion", "expected"),
+    [
+        ("completed", "failure", True),
+        ("completed", "cancelled", True),
+        ("completed", "timed_out", True),
+        ("in_progress", "failure", False),
+        ("completed", "success", False),
+        ("queued", None, False),
+    ],
+)
+def test_recovery_requires_a_confirmed_failed_owner(
+    monkeypatch, status, conclusion, expected
+):
+    import importlib.util
+
+    spec = importlib.util.spec_from_file_location(
+        "check_uk_owner_for_test", REPO_ROOT / "scripts/check_uk_candidate.py"
+    )
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+    calls = []
+
+    def run(argv, **kwargs):
+        calls.append(argv)
+        return subprocess.CompletedProcess(
+            argv, 0, json.dumps({"status": status, "conclusion": conclusion})
+        )
+
+    monkeypatch.setattr(cli, "subprocess", SimpleNamespace(run=run))
+    assert cli.owner_run_failed("42") is expected
+    assert "42" in calls[0] and cli.LEDGER_REPOSITORY in calls[0]
+    cli.owner_run_failed.cache_clear()
+    monkeypatch.setattr(
+        cli,
+        "subprocess",
+        SimpleNamespace(run=lambda *a, **k: subprocess.CompletedProcess(a, 1, "")),
+    )
+    assert not cli.owner_run_failed("42")
+
+
+def test_catchup_finds_abandoned_stages_without_replay_requests(
+    tmp_path, monkeypatch, capsys
+):
+    import importlib.util
+
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    spec = importlib.util.spec_from_file_location(
+        "check_uk_recovery_for_test", REPO_ROOT / "scripts/check_uk_candidate.py"
+    )
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+    pair = make_pair()
+    attempt = attempt_directory(tmp_path, "uk", pair.pair_id, "a" * 12)
+    payload = {"pair": pair.canonical_payload()}
+    stage_attempt(attempt, payload, HARNESS)
+    write_json(
+        attempt / "staging.json",
+        {
+            "sequence": 1,
+            "owner_run_id": "42",
+            "expires_at": "2026-10-14T14:00:00Z",
+        },
+    )
+    monkeypatch.setattr(cli, "utc_now", lambda: "2026-10-14T11:00:00Z")
+    monkeypatch.setattr(cli, "owner_run_failed", lambda run_id: run_id == "42")
+    assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
+    assert json.loads(capsys.readouterr().out) == payload
+    replacement = attempt_directory(tmp_path, "uk", pair.pair_id, "a" * 12 + "-2")
+    stage_attempt(
+        replacement,
+        payload,
+        HARNESS,
+        owner_run_id="43",
+        staged_at="2026-10-14T11:00:00Z",
+    )
+    assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
+    assert capsys.readouterr().out == ""
+    write_json(
+        attempt / "staging.json",
+        {
+            "sequence": 3,
+            "owner_run_id": "42",
+            "expires_at": "2026-10-14T14:00:00Z",
+        },
+    )
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        make_receipt(pair=pair).canonical_payload(),
+    )
+    assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
+    assert capsys.readouterr().out == ""
+
+
 def test_attempt_lifecycle(tmp_path):
     from policyengine.provenance.qualification import GateResult
     from policyengine.provenance.qualification_ledger import (
diff --git a/tests/test_uk_qualification_workflow.py b/tests/test_uk_qualification_workflow.py
new file mode 100644
index 00000000..896cda51
--- /dev/null
+++ b/tests/test_uk_qualification_workflow.py
@@ -0,0 +1,331 @@
+"""Qualification workflow readiness and failed-check refresh (no remote writes)."""
+
+from __future__ import annotations
+
+import argparse
+import importlib.util
+import json
+import os
+import subprocess
+import sys
+from pathlib import Path
+from types import SimpleNamespace
+
+import pytest
+import yaml
+
+from policyengine.provenance.uk_qualification import accept_review, candidate_branch
+from tests.qualification_fixtures import gates, make_pair, make_receipt
+
+REPO_ROOT = Path(__file__).resolve().parents[1]
+WORKFLOW_PATH = REPO_ROOT / ".github/workflows/certify-uk-release.yaml"
+
+
+def _cli():
+    spec = importlib.util.spec_from_file_location(
+        "qualification_workflow_cli", REPO_ROOT / "scripts/check_uk_candidate.py"
+    )
+    module = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(module)
+    return module
+
+
+def _workflow():
+    return yaml.safe_load(WORKFLOW_PATH.read_text())
+
+
+def test_resolution_can_authenticate_the_staged_attempt_owner_lookup():
+    resolve = _workflow()["jobs"]["resolve"]
+    assert resolve["permissions"]["contents"] == "read"
+    assert resolve["permissions"]["actions"] == "read"
+    step = next(
+        step
+        for step in resolve["steps"]
+        if step.get("name") == "Resolve and deduplicate the candidate"
+    )
+    assert step["env"]["GH_TOKEN"] == "${{ github.token }}"
+
+
+@pytest.mark.parametrize("prepare_first", [False, True])
+def test_head_replacement_and_readiness_share_one_serialization(
+    monkeypatch, tmp_path, prepare_first
+):
+    """Replay a branch replacement after the real promotion's head snapshot.
+
+    The scheduler's locks come from the workflow, and preparation executes its
+    actual draft-and-push shell with command stand-ins. Different lock groups
+    allow the reviewer's failing interleaving; one shared group defers it.
+    """
+
+    cli = _cli()
+    workflow = _workflow()
+    jobs = workflow["jobs"]
+    bundle = json.loads(cli.BUNDLE_PATH.read_text())
+    qualified = make_receipt(
+        pair=make_pair(
+            model="2.200.0",
+            data=bundle["data_releases"]["uk"]["data_package"]["version"],
+            core=bundle["packages"]["policyengine-core"]["version"],
+        )
+    )
+    branch = candidate_branch(qualified.pair)
+    state_path = tmp_path / "state.json"
+    state_path.write_text(
+        json.dumps({"status": "ready", "head": qualified.harness.git_commit})
+    )
+    new_head = "f" * 40
+    binary_dir = tmp_path / "bin"
+    binary_dir.mkdir()
+    fake = f"""#!{sys.executable}
+import json, os, sys
+from pathlib import Path
+path = Path(os.environ["PR_STATE"])
+state = json.loads(path.read_text())
+command, args = Path(sys.argv[0]).name, sys.argv[1:]
+if command == "gh" and args[:2] == ["pr", "list"]:
+    if state["status"] == "ready":
+        print("574")
+elif command == "gh" and args[:2] == ["pr", "ready"]:
+    assert args[2:] == ["574", "--undo"]
+    state["status"] = "draft"
+    path.write_text(json.dumps(state))
+elif command == "git" and args[0] == "push":
+    assert state["status"] == "draft"
+    state["head"] = {new_head!r}
+    path.write_text(json.dumps(state))
+"""
+    for command in ("gh", "git"):
+        executable = binary_dir / command
+        executable.write_text(fake)
+        executable.chmod(0o755)
+    push_step = next(
+        step
+        for step in jobs["prepare"]["steps"]
+        if step.get("name") == "Commit and push the candidate commit"
+    )
+    groups = {
+        job: jobs[job]["concurrency"]["group"].replace(
+            "${{ needs.resolve.outputs.pair_id }}", qualified.pair_id
+        )
+        for job in ("prepare", "promote")
+    }
+    running = set()
+    deferred = []
+    ready_heads = []
+
+    def prepare():
+        subprocess.run(
+            ["bash", "-e", "-o", "pipefail", "-c", push_step["run"]],
+            cwd=tmp_path,
+            env={
+                **os.environ,
+                "PATH": f"{binary_dir}{os.pathsep}{os.environ['PATH']}",
+                "BRANCH": branch,
+                "PAIR_ID": qualified.pair_id,
+                "PR_STATE": str(state_path),
+            },
+            check=True,
+            capture_output=True,
+            timeout=30,
+        )
+
+    def schedule(job, operation):
+        if groups[job] in running:
+            deferred.append((job, operation))
+            return
+        running.add(groups[job])
+        try:
+            operation()
+        finally:
+            running.remove(groups[job])
+
+    def fake_run(argv, **kwargs):
+        if argv[:3] == ["gh", "pr", "list"]:
+            state = json.loads(state_path.read_text())
+            return SimpleNamespace(
+                stdout=json.dumps(
+                    [{"headRefName": branch, "headRefOid": state["head"]}]
+                )
+            )
+        assert argv[:3] == ["gh", "pr", "ready"]
+        if not prepare_first:
+            schedule("prepare", prepare)
+        state = json.loads(state_path.read_text())
+        ready_heads.append(state["head"])
+        state["status"] = "ready"
+        state_path.write_text(json.dumps(state))
+        return SimpleNamespace(returncode=0)
+
+    monkeypatch.setattr(cli, "latest_receipts", lambda root: [qualified])
+    monkeypatch.setattr(cli, "subprocess", SimpleNamespace(run=fake_run))
+    monkeypatch.setattr(cli, "config", lambda: {"promotion": {"automatic": False}})
+    if prepare_first:
+        schedule("prepare", prepare)
+    schedule(
+        "promote",
+        lambda: cli.cmd_promote(argparse.Namespace(ledger=str(tmp_path), apply=True)),
+    )
+    for job, operation in deferred:
+        schedule(job, operation)
+    assert all(head == qualified.harness.git_commit for head in ready_heads)
+    assert json.loads(state_path.read_text()) == {"status": "draft", "head": new_head}
+    assert jobs["prepare"]["concurrency"]["cancel-in-progress"] is False
+    assert jobs["promote"]["concurrency"]["cancel-in-progress"] is False
+
+
+@pytest.mark.parametrize("job", ["replay", "catch-up", "accept"])
+def test_workflow_refreshes_failed_checks_after_publishing_receipts(job):
+    workflow = _workflow()
+    configured = workflow["jobs"][job]
+    refresh = next(
+        step
+        for step in configured["steps"]
+        if "refresh-pr-checks" in step.get("run", "")
+    )
+    assert configured["permissions"]["actions"] == "write"
+    assert refresh["env"]["GH_TOKEN"] == "${{ github.token }}"
+    steps = configured["steps"]
+    publish_positions = [
+        index
+        for index, step in enumerate(steps)
+        if ".github/qualification-ledger.sh publish" in step.get("run", "")
+    ]
+    assert publish_positions
+    assert max(publish_positions) < steps.index(refresh)
+
+
+def test_catch_up_dispatches_recovery_for_the_original_pair(tmp_path):
+    workflow = _workflow()
+    job = workflow["jobs"]["catch-up"]
+    step = next(
+        step for step in job["steps"] if "recoverable --ledger" in step.get("run", "")
+    )
+    pair = make_pair(model="2.200.0", data="1.58.9")
+    candidate_path = tmp_path / "candidate.json"
+    candidate_path.write_text(json.dumps({"pair": pair.canonical_payload()}))
+    command_log = tmp_path / "commands.jsonl"
+    binary_dir = tmp_path / "bin"
+    binary_dir.mkdir()
+    fake = f"""#!{sys.executable}
+import json, os, sys
+from pathlib import Path
+command, args = Path(sys.argv[0]).name, sys.argv[1:]
+if command == "python":
+    if args == ["scripts/check_uk_candidate.py", "recoverable", "--ledger", "ledger"]:
+        assert Path("ledger").is_dir()
+        print(Path(os.environ["RECOVERY_CANDIDATE"]).read_text())
+    else:
+        assert args == ["-"]
+        os.execv(sys.executable, [sys.executable, *args])
+else:
+    assert command == "gh"
+    assert Path("ledger").is_dir()
+    with Path(os.environ["COMMAND_LOG"]).open("a") as stream:
+        stream.write(json.dumps(args) + "\\n")
+"""
+    for command in ("python", "gh"):
+        executable = binary_dir / command
+        executable.write_text(fake)
+        executable.chmod(0o755)
+    ledger_script = tmp_path / ".github" / "qualification-ledger.sh"
+    ledger_script.parent.mkdir()
+    ledger_script.write_text("#!/bin/bash\nset -e\nmkdir ledger\n")
+    ledger_script.chmod(0o755)
+    subprocess.run(
+        ["bash", "-e", "-o", "pipefail", "-c", step["run"]],
+        cwd=tmp_path,
+        env={
+            **os.environ,
+            "PATH": f"{binary_dir}{os.pathsep}{os.environ['PATH']}",
+            "RECOVERY_CANDIDATE": str(candidate_path),
+            "COMMAND_LOG": str(command_log),
+            "GITHUB_REPOSITORY": "PolicyEngine/policyengine.py",
+        },
+        check=True,
+        capture_output=True,
+        timeout=30,
+    )
+    assert [json.loads(line) for line in command_log.read_text().splitlines()] == [
+        [
+            "workflow",
+            "run",
+            "certify-uk-release.yaml",
+            "--repo",
+            "PolicyEngine/policyengine.py",
+            "--ref",
+            "main",
+            "-f",
+            "model_version=2.200.0",
+            "-f",
+            "data_version=1.58.9",
+            "-f",
+            "force=false",
+        ]
+    ]
+    assert job["permissions"]["actions"] == "write"
+    assert step["env"]["GH_TOKEN"] == "${{ github.token }}"
+
+
+@pytest.mark.parametrize("head_matches", [False, True])
+@pytest.mark.parametrize("verdict", ["qualified", "rejected", "accepted_review"])
+def test_refresh_checks_reruns_only_failed_pr_runs_for_the_qualified_head(
+    monkeypatch, tmp_path, head_matches, verdict
+):
+    cli = _cli()
+    receipt = make_receipt(
+        gate_results={
+            "qualified": gates(),
+            "rejected": gates(replay="fail"),
+            "accepted_review": gates(metrics_review="needs_review"),
+        }[verdict]
+    )
+    if verdict == "accepted_review":
+        receipt = accept_review(
+            receipt,
+            reviewer="reviewer",
+            accepted_receipt_sha256=receipt.unreviewed_sha256,
+            explanation="Expected change checked by the reviewer.",
+            accepted_at="2026-10-16T09:00:00Z",
+        )
+    branch = candidate_branch(receipt.pair)
+    head = receipt.harness.git_commit if head_matches else "f" * 40
+    monkeypatch.setattr(cli, "latest_receipts", lambda root: [receipt])
+    monkeypatch.setattr(cli, "_open_candidate_branches", lambda: {branch: head})
+    runs = [
+        {
+            "id": identifier,
+            "head_sha": sha,
+            "event": event,
+            "status": status,
+            "conclusion": conclusion,
+        }
+        for identifier, sha, event, status, conclusion in (
+            (11, head, "pull_request", "completed", "failure"),
+            (12, head, "pull_request", "completed", "success"),
+            (13, head, "pull_request", "in_progress", "failure"),
+            (14, "a" * 40, "pull_request", "completed", "failure"),
+            (15, head, "push", "completed", "failure"),
+            (16, head, "pull_request", "completed", "timed_out"),
+        )
+    ]
+    calls = []
+
+    def fake_run(argv, **kwargs):
+        calls.append(argv)
+        if argv[:2] == ["gh", "api"]:
+            assert "--paginate" in argv
+            assert f"head_sha={receipt.harness.git_commit}" in argv[2]
+            assert "event=pull_request" in argv[2]
+            return SimpleNamespace(stdout="\n".join(json.dumps(run) for run in runs))
+        assert argv[:3] == ["gh", "run", "rerun"]
+        assert "--failed" in argv and kwargs["check"] is True
+        return SimpleNamespace(returncode=0)
+
+    monkeypatch.setattr(cli, "subprocess", SimpleNamespace(run=fake_run))
+    args = cli.parser().parse_args(["refresh-pr-checks", "--ledger", str(tmp_path)])
+    assert args.func(args) == 0
+    reruns = [call[3] for call in calls if call[:3] == ["gh", "run", "rerun"]]
+    if receipt.promotable and head_matches:
+        assert reruns == ["11", "16"]
+    else:
+        assert calls == []

From b182e956af7781d97d7fd2b0d32505ada60d0351 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Wed, 14 Oct 2026 08:43:34 -0400
Subject: [PATCH 29/45] Check the UC allowance response on the award before
 deductions

W1's population_uc_standard_allowance_plus_10 required that no
universal_credit amount fall when every standard allowance rises 10%.
universal_credit is the amount paid, net of deductions. Under the benefit
cap (Universal Credit Regulations 2013, SI 2013/376, reg 81) a capped award
stays flat, and deductions are taken from the award as percentages of the
standard allowance (Claims and Payments Regulations 2013, SI 2013/380,
Sch 6), so a capped claimant with deductions is paid less. policyengine-uk
2.130.1 applies deductions to simulations built from data (#1905), so one
benefit unit in the 1,000-household subsample shows exactly that; 2.126.12
applied none below 1e6 benefit-unit weight, so the subsample never had
deductions.

The check now asserts what the law makes invariant:
- no award before deductions (universal_credit_pre_benefit_cap less
  benefit_cap_reduction) falls;
- no payment falls by more than its deductions rise;
- no deductions rise by more than the standard allowance;
plus, as before, exact 10% scaling and at least one higher payment.
The verdict is a pure function, uc_allowance_verdict, with a test for the
lawful capped case and one for each unlawful movement.

Co-Authored-By: Claude Opus 5.5 
---
 .../uk/budget_reform_population.py            |  94 +++++++++++++---
 tests/test_uk_budget_reform_contract.py       | 101 ++++++++++++++++++
 2 files changed, 179 insertions(+), 16 deletions(-)

diff --git a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
index 9a0a7974..9fe5bb8c 100644
--- a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
+++ b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
@@ -26,7 +26,16 @@
 ``population_uc_standard_allowance_plus_10``
     Every Universal Credit standard allowance 10% higher in 2027-28 raises
     each benefit unit's standard allowance by exactly 10%, lowers no award
-    and raises total Universal Credit.
+    before deductions and raises total Universal Credit. The award before
+    deductions is ``universal_credit_pre_benefit_cap`` less
+    ``benefit_cap_reduction``: the benefit cap reduces the award by the
+    excess of welfare benefits over the cap (Universal Credit Regulations
+    2013, SI 2013/376, reg 81), so a capped award stays flat. Deductions are
+    then taken from the award and set as percentages of the standard
+    allowance (Claims and Payments Regulations 2013, SI 2013/380, Sch 6), so
+    the amount paid (``universal_credit``) can fall. The check bounds that
+    fall: no payment falls by more than its deductions rise, and no
+    deductions rise by more than the standard allowance.
 ``population_state_pension_plus_10``
     The basic and new State Pension rates 10% higher in 2027-28 raise each
     person's basic and new State Pension by exactly 10% and raise total
@@ -93,6 +102,66 @@ def population_check_routes(routes: Sequence[str]) -> tuple[tuple[str, str], ...
     )
 
 
+#: What the Universal Credit allowance check reads from each simulation.
+UC_ALLOWANCE_VARIABLES = (
+    "uc_standard_allowance",
+    "universal_credit",
+    "universal_credit_pre_benefit_cap",
+    "benefit_cap_reduction",
+    "uc_deductions",
+)
+
+
+def uc_allowance_verdict(
+    base: dict[str, np.ndarray], reformed: dict[str, np.ndarray]
+) -> tuple[bool, dict]:
+    """Whether a 10% higher standard allowance moved Universal Credit lawfully.
+
+    ``base`` and ``reformed`` hold ``UC_ALLOWANCE_VARIABLES`` per benefit
+    unit. The benefit cap reduces the award by the excess of welfare benefits
+    over the cap (SI 2013/376 reg 81), so a capped award stays flat and no
+    award before deductions may fall. Deductions are taken from the award as
+    percentages of the standard allowance (SI 2013/380 Sch 6), so the amount
+    paid may fall, but by no more than the deductions rise, and deductions
+    may rise by no more than the standard allowance.
+    """
+
+    allowance, base_allowance = (
+        reformed["uc_standard_allowance"],
+        base["uc_standard_allowance"],
+    )
+    scaled = bool(np.allclose(allowance, 1.1 * base_allowance, rtol=1e-6))
+    award = (
+        reformed["universal_credit_pre_benefit_cap"] - reformed["benefit_cap_reduction"]
+    )
+    base_award = (
+        base["universal_credit_pre_benefit_cap"] - base["benefit_cap_reduction"]
+    )
+    paid, base_paid = reformed["universal_credit"], base["universal_credit"]
+    deduction_rise = reformed["uc_deductions"] - base["uc_deductions"]
+    awards_lower = int(np.sum(award < base_award - 1e-3))
+    payments_higher = int(np.sum(paid > base_paid + 1e-3))
+    beyond_deductions = int(
+        np.sum((base_paid - paid) - np.maximum(deduction_rise, 0) > 1e-3)
+    )
+    beyond_allowance = int(np.sum(deduction_rise - (allowance - base_allowance) > 1e-3))
+    holds = (
+        scaled
+        and awards_lower == 0
+        and beyond_deductions == 0
+        and beyond_allowance == 0
+        and payments_higher > 0
+    )
+    return holds, {
+        "standard_allowance_scaled_10_percent": scaled,
+        "awards_lower": awards_lower,
+        "payments_lower": int(np.sum(paid < base_paid - 1e-3)),
+        "payments_higher": payments_higher,
+        "payment_falls_beyond_deduction_rises": beyond_deductions,
+        "deduction_rises_beyond_allowance_rises": beyond_allowance,
+    }
+
+
 def plus_ten_percent(paths: Sequence[str]) -> dict:
     """Each parameter 10% above current law for the response year."""
     from policyengine_uk.system import system
@@ -314,8 +383,7 @@ def values(simulation, variable):
         base = {
             variable: values(unreformed, variable)
             for variable in (
-                "uc_standard_allowance",
-                "universal_credit",
+                *UC_ALLOWANCE_VARIABLES,
                 "basic_state_pension",
                 "new_state_pension",
                 "state_pension",
@@ -323,23 +391,17 @@ def values(simulation, variable):
         }
         for route in country:
             simulation = build(route, plus_ten_percent(UC_STANDARD_ALLOWANCES))
-            allowance = values(simulation, "uc_standard_allowance")
-            award = values(simulation, "universal_credit")
-            scaled = bool(
-                np.allclose(allowance, 1.1 * base["uc_standard_allowance"], rtol=1e-6)
-            )
-            lower = int(np.sum(award < base["universal_credit"] - 1e-3))
-            higher = int(np.sum(award > base["universal_credit"] + 1e-3))
+            uc_reformed = {
+                variable: values(simulation, variable)
+                for variable in UC_ALLOWANCE_VARIABLES
+            }
+            holds, detail = uc_allowance_verdict(base, uc_reformed)
             rows.append(
                 _row(
                     "population_uc_standard_allowance_plus_10",
                     route,
-                    "pass" if scaled and lower == 0 and higher > 0 else "fail",
-                    detail={
-                        "standard_allowance_scaled_10_percent": scaled,
-                        "awards_lower": lower,
-                        "awards_higher": higher,
-                    },
+                    "pass" if holds else "fail",
+                    detail=detail,
                 )
             )
         for route in country:
diff --git a/tests/test_uk_budget_reform_contract.py b/tests/test_uk_budget_reform_contract.py
index a4113e2b..0706369c 100644
--- a/tests/test_uk_budget_reform_contract.py
+++ b/tests/test_uk_budget_reform_contract.py
@@ -620,3 +620,104 @@ def test_household_result_totals_read_each_variable_from_its_own_entity():
     assert _result_total(result, "income_tax") == 150.0
     with pytest.raises(KeyError, match="benunit"):
         _result_total({"household": {"universal_credit": 1.0}}, "universal_credit")
+
+
+# The Universal Credit allowance check's verdict, on synthetic benefit units.
+
+
+def _uc_units(**columns):
+    import numpy as np
+
+    defaults = {
+        "uc_standard_allowance": [400.0],
+        "universal_credit": [500.0],
+        "universal_credit_pre_benefit_cap": [500.0],
+        "benefit_cap_reduction": [0.0],
+        "uc_deductions": [0.0],
+    }
+    defaults.update(columns)
+    return {name: np.array(values, dtype=float) for name, values in defaults.items()}
+
+
+def _verdict(base, reformed):
+    from policyengine.tax_benefit_models.uk.budget_reform_population import (
+        uc_allowance_verdict,
+    )
+
+    return uc_allowance_verdict(base, reformed)
+
+
+def _lawful_pair():
+    """A capped unit with deductions and an uncapped unit that gains."""
+
+    base = _uc_units(
+        uc_standard_allowance=[400.0, 400.0],
+        universal_credit_pre_benefit_cap=[900.0, 500.0],
+        benefit_cap_reduction=[100.0, 0.0],
+        uc_deductions=[20.0, 0.0],
+        universal_credit=[780.0, 500.0],
+    )
+    reformed = _uc_units(
+        uc_standard_allowance=[440.0, 440.0],
+        universal_credit_pre_benefit_cap=[940.0, 540.0],
+        benefit_cap_reduction=[140.0, 0.0],
+        uc_deductions=[22.0, 0.0],
+        universal_credit=[778.0, 540.0],
+    )
+    return base, reformed
+
+
+def test_a_capped_award_whose_deductions_rise_with_the_allowance_holds():
+    """SI 2013/376 reg 81 holds a capped award flat; SI 2013/380 Sch 6
+    deductions scale with the allowance, so the amount paid can fall."""
+
+    base, reformed = _lawful_pair()
+    holds, detail = _verdict(base, reformed)
+    assert holds, detail
+    assert detail["payments_lower"] == 1
+    assert detail["awards_lower"] == 0
+
+
+@pytest.mark.parametrize(
+    ("change", "failing_key", "passing_value"),
+    [
+        ({"benefit_cap_reduction": 150.0}, "awards_lower", 0),
+        (
+            {"universal_credit": 770.0},
+            "payment_falls_beyond_deduction_rises",
+            0,
+        ),
+        (
+            {"uc_deductions": 70.0, "universal_credit": 730.0},
+            "deduction_rises_beyond_allowance_rises",
+            0,
+        ),
+        (
+            {"uc_standard_allowance": 430.0},
+            "standard_allowance_scaled_10_percent",
+            True,
+        ),
+    ],
+    ids=[
+        "award-falls",
+        "payment-falls-beyond-deductions",
+        "deductions-beyond-allowance",
+        "not-scaled",
+    ],
+)
+def test_the_uc_allowance_check_fails_on_each_unlawful_movement(
+    change, failing_key, passing_value
+):
+    base, reformed = _lawful_pair()
+    assert _verdict(base, reformed)[0]
+    for name, value in change.items():
+        reformed[name][0] = value
+    holds, detail = _verdict(base, reformed)
+    assert not holds
+    assert detail[failing_key] != passing_value, detail
+
+
+def test_the_uc_allowance_check_fails_when_no_payment_rises():
+    base = _uc_units()
+    holds, detail = _verdict(base, _uc_units(uc_standard_allowance=[440.0]))
+    assert not holds and detail["payments_higher"] == 0

From c9ecb382783fec42e8ecbd04d422168d8d983319 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Wed, 14 Oct 2026 08:46:26 -0400
Subject: [PATCH 30/45] Bound UC deduction rises by each unit's own rate

The UK hub pointed out that "deductions rise by no more than the standard
allowance" holds only while uc_deduction_rate <= 1: policyengine-uk 2.130.1
adds the latent excess above the deductions cap (deductions the cap does not
limit) with no bound of its own. The check now requires that no unit's
deduction rate changes under the reform (the rate does not depend on the
allowance) and that its deductions rise by no more than that rate times the
allowance rise, which is tighter for ordinary rates and still correct above
1. Tests cover a rate above 1 and a changed rate.

Co-Authored-By: Claude Opus 5.5 
---
 .../uk/budget_reform_population.py            | 29 ++++++++++++++-----
 tests/test_uk_budget_reform_contract.py       | 22 ++++++++++++--
 2 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
index 9fe5bb8c..3a2d65af 100644
--- a/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
+++ b/src/policyengine/tax_benefit_models/uk/budget_reform_population.py
@@ -34,8 +34,9 @@
     then taken from the award and set as percentages of the standard
     allowance (Claims and Payments Regulations 2013, SI 2013/380, Sch 6), so
     the amount paid (``universal_credit``) can fall. The check bounds that
-    fall: no payment falls by more than its deductions rise, and no
-    deductions rise by more than the standard allowance.
+    fall: no payment falls by more than its deductions rise, no unit's
+    deduction rate changes, and no deductions rise by more than that rate
+    times the standard allowance rise.
 ``population_state_pension_plus_10``
     The basic and new State Pension rates 10% higher in 2027-28 raise each
     person's basic and new State Pension by exactly 10% and raise total
@@ -109,6 +110,7 @@ def population_check_routes(routes: Sequence[str]) -> tuple[tuple[str, str], ...
     "universal_credit_pre_benefit_cap",
     "benefit_cap_reduction",
     "uc_deductions",
+    "uc_deduction_rate",
 )
 
 
@@ -122,8 +124,13 @@ def uc_allowance_verdict(
     over the cap (SI 2013/376 reg 81), so a capped award stays flat and no
     award before deductions may fall. Deductions are taken from the award as
     percentages of the standard allowance (SI 2013/380 Sch 6), so the amount
-    paid may fall, but by no more than the deductions rise, and deductions
-    may rise by no more than the standard allowance.
+    paid may fall, but by no more than the deductions rise. In the model a
+    unit's deductions are its ``uc_deduction_rate`` times the standard
+    allowance, capped by the award; the rate does not depend on the
+    allowance, so it must not change, and deductions may rise by no more
+    than that rate times the allowance rise. (The rate can exceed 1: the
+    excess above the deductions cap, for deductions the cap does not limit,
+    has no bound of its own.)
     """
 
     allowance, base_allowance = (
@@ -139,17 +146,24 @@ def uc_allowance_verdict(
     )
     paid, base_paid = reformed["universal_credit"], base["universal_credit"]
     deduction_rise = reformed["uc_deductions"] - base["uc_deductions"]
+    rate = reformed["uc_deduction_rate"]
+    rates_changed = int(
+        np.sum(~np.isclose(rate, base["uc_deduction_rate"], rtol=1e-9, atol=1e-12))
+    )
     awards_lower = int(np.sum(award < base_award - 1e-3))
     payments_higher = int(np.sum(paid > base_paid + 1e-3))
     beyond_deductions = int(
         np.sum((base_paid - paid) - np.maximum(deduction_rise, 0) > 1e-3)
     )
-    beyond_allowance = int(np.sum(deduction_rise - (allowance - base_allowance) > 1e-3))
+    beyond_rate = int(
+        np.sum(deduction_rise - rate * (allowance - base_allowance) > 1e-3)
+    )
     holds = (
         scaled
         and awards_lower == 0
         and beyond_deductions == 0
-        and beyond_allowance == 0
+        and rates_changed == 0
+        and beyond_rate == 0
         and payments_higher > 0
     )
     return holds, {
@@ -158,7 +172,8 @@ def uc_allowance_verdict(
         "payments_lower": int(np.sum(paid < base_paid - 1e-3)),
         "payments_higher": payments_higher,
         "payment_falls_beyond_deduction_rises": beyond_deductions,
-        "deduction_rises_beyond_allowance_rises": beyond_allowance,
+        "deduction_rates_changed": rates_changed,
+        "deduction_rises_beyond_rate_times_allowance_rise": beyond_rate,
     }
 
 
diff --git a/tests/test_uk_budget_reform_contract.py b/tests/test_uk_budget_reform_contract.py
index 0706369c..591262a6 100644
--- a/tests/test_uk_budget_reform_contract.py
+++ b/tests/test_uk_budget_reform_contract.py
@@ -634,6 +634,7 @@ def _uc_units(**columns):
         "universal_credit_pre_benefit_cap": [500.0],
         "benefit_cap_reduction": [0.0],
         "uc_deductions": [0.0],
+        "uc_deduction_rate": [0.0],
     }
     defaults.update(columns)
     return {name: np.array(values, dtype=float) for name, values in defaults.items()}
@@ -655,6 +656,7 @@ def _lawful_pair():
         universal_credit_pre_benefit_cap=[900.0, 500.0],
         benefit_cap_reduction=[100.0, 0.0],
         uc_deductions=[20.0, 0.0],
+        uc_deduction_rate=[0.05, 0.0],
         universal_credit=[780.0, 500.0],
     )
     reformed = _uc_units(
@@ -662,6 +664,7 @@ def _lawful_pair():
         universal_credit_pre_benefit_cap=[940.0, 540.0],
         benefit_cap_reduction=[140.0, 0.0],
         uc_deductions=[22.0, 0.0],
+        uc_deduction_rate=[0.05, 0.0],
         universal_credit=[778.0, 540.0],
     )
     return base, reformed
@@ -688,10 +691,11 @@ def test_a_capped_award_whose_deductions_rise_with_the_allowance_holds():
             0,
         ),
         (
-            {"uc_deductions": 70.0, "universal_credit": 730.0},
-            "deduction_rises_beyond_allowance_rises",
+            {"uc_deductions": 30.0, "universal_credit": 770.0},
+            "deduction_rises_beyond_rate_times_allowance_rise",
             0,
         ),
+        ({"uc_deduction_rate": 0.06}, "deduction_rates_changed", 0),
         (
             {"uc_standard_allowance": 430.0},
             "standard_allowance_scaled_10_percent",
@@ -701,7 +705,8 @@ def test_a_capped_award_whose_deductions_rise_with_the_allowance_holds():
     ids=[
         "award-falls",
         "payment-falls-beyond-deductions",
-        "deductions-beyond-allowance",
+        "deductions-beyond-rate",
+        "rate-changed",
         "not-scaled",
     ],
 )
@@ -721,3 +726,14 @@ def test_the_uc_allowance_check_fails_when_no_payment_rises():
     base = _uc_units()
     holds, detail = _verdict(base, _uc_units(uc_standard_allowance=[440.0]))
     assert not holds and detail["payments_higher"] == 0
+
+
+def test_a_deduction_rate_above_one_bounds_by_the_rate_not_the_allowance():
+    """Deductions the cap does not limit can exceed the standard allowance."""
+
+    base, reformed = _lawful_pair()
+    base["uc_deduction_rate"][0] = reformed["uc_deduction_rate"][0] = 1.5
+    base["uc_deductions"][0], reformed["uc_deductions"][0] = 600.0, 660.0
+    base["universal_credit"][0], reformed["universal_credit"][0] = 200.0, 140.0
+    holds, detail = _verdict(base, reformed)
+    assert holds, detail

From 769d5efa1a1db83df3e3cc9e8e8fdaff928be735 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Thu, 15 Oct 2026 07:35:47 -0400
Subject: [PATCH 31/45] Require the current baseline before promotion; recover
 forced attempts across bases

Round-5 review findings on #574:

- A dominant candidate qualified against an older certificate could be
  readied after another candidate became main, though baseline-dependent
  gates (supported years, metrics, responsiveness) would fail against the
  new main: C dropped 2032 that B had added. Promotion now requires the
  target's full previous certificate to equal current main's before it
  readies the target or lets it close other candidates. A stale target is
  reported with an instruction to requalify with --force against main.
- An authorized forced replacement that expired stayed draft forever once
  main advanced, because recovery looked only at the current base's
  attempts. Recovery and key allocation now follow the pair's newest
  staged attempt across bases, keeping the exact superseded-receipt
  binding, owner and expiry checks, and the protection of newer work.

Co-Authored-By: GPT-6.1 Sol via Subfleet 
Co-Authored-By: Claude Opus 5.5 
---
 .../provenance/uk_qualification.py            |  50 ++-
 tests/test_uk_qualification_pipeline.py       | 305 +++++++++++++++++-
 tests/test_uk_qualification_workflow.py       |   8 +-
 3 files changed, 340 insertions(+), 23 deletions(-)

diff --git a/src/policyengine/provenance/uk_qualification.py b/src/policyengine/provenance/uk_qualification.py
index 39965c33..6d711cfc 100644
--- a/src/policyengine/provenance/uk_qualification.py
+++ b/src/policyengine/provenance/uk_qualification.py
@@ -391,13 +391,14 @@ def candidate_action(
         else None
     )
     attempt = _latest_base_attempt(pair, ledger_root, base_commit)
+    recovery = _latest_staged_attempt(pair, ledger_root)
     if (
-        attempt is not None
-        and attempt_is_recoverable(attempt, now=now, owner_is_failed=owner_is_failed)
+        recovery is not None
+        and attempt_is_recoverable(recovery, now=now, owner_is_failed=owner_is_failed)
         and (
             receipt is None
             or receipt.verdict == "incomplete"
-            or attempt_supersedes_receipt(attempt, receipt)
+            or attempt_supersedes_receipt(recovery, receipt)
         )
     ):
         return "qualify", "recoverable abandoned staged attempt"
@@ -500,13 +501,14 @@ def attempt_key(
 
     Concurrent runs for the same pair and base deduplicate. Forced runs and
     recovery of abandoned stages use the next free key, preserving earlier
-    evidence. A live replacement blocks further recovery on that base.
+    evidence. Recovery follows the newest stage across bases so an unrelated
+    main commit cannot strand an authorized forced replacement.
     """
 
     key = base_commit[:12]
     if ledger_root is None:
         return key
-    attempt = _latest_base_attempt(pair, ledger_root, base_commit)
+    attempt = _latest_staged_attempt(pair, ledger_root)
     recovering = attempt is not None and attempt_is_recoverable(
         attempt, now=now, owner_is_failed=owner_is_failed
     )
@@ -522,6 +524,23 @@ def attempt_key(
     return f"{key}-{repeat}"
 
 
+def _latest_staged_attempt(pair: CandidatePair, ledger_root: Path) -> Optional[Path]:
+    """The pair's newest durable stage, independent of its main base commit.
+
+    A newer stage supersedes older recovery work across bases. Inspecting just
+    the current base could overlook abandoned forced work or retry an older
+    stage while its replacement is live.
+    """
+
+    parent = pair_directory(ledger_root, "uk", pair.pair_id) / "attempts"
+    stage = max(
+        parent.glob("*/staging.json"),
+        key=lambda path: int(read_json(path)["sequence"]),
+        default=None,
+    )
+    return stage.parent if stage is not None else None
+
+
 def _latest_base_attempt(
     pair: CandidatePair, ledger_root: Path, base_commit: str
 ) -> Optional[Path]:
@@ -1201,12 +1220,18 @@ def plan_promotion(
     commit. The target's branch is readied only while its head is exactly
     the commit the target's qualification ran on
     (``receipt.harness.git_commit``): the replayed and tested bytes are the
-    promoted bytes. A branch that moved since is left alone and reported.
+    promoted bytes. The comparison certificate must also still equal main's;
+    otherwise the candidate needs a forced qualification of all gates against
+    the current baseline. A stale baseline cannot supersede other candidates.
+    A branch that moved since is left alone and reported.
     """
 
     receipts = list(receipts)
     current = certified_order_key(bundle)
     target = select_promotion_target(receipts, current)
+    baseline_matches = target is not None and (
+        target.previous_certificate == previous_certificate(bundle)
+    )
     branch_pairs = {}
     for receipt in receipts:
         branch_pairs[candidate_branch(receipt.pair)] = receipt.pair.order_key
@@ -1217,7 +1242,7 @@ def plan_promotion(
             continue
         if key == current or dominates(current, key):
             close.append(branch)
-        elif target is not None and dominates(target.pair.order_key, key):
+        elif baseline_matches and dominates(target.pair.order_key, key):
             close.append(branch)
     if target is None:
         return PromotionPlan(
@@ -1226,6 +1251,17 @@ def plan_promotion(
             close_branches=sorted(close),
             reason=f"no promotable pair advances {current}",
         )
+    if not baseline_matches:
+        return PromotionPlan(
+            target=target,
+            ready_branch=None,
+            close_branches=sorted(close),
+            reason=(
+                f"{target.pair.order_key} advances {current}, but its previous "
+                "certificate differs from current main; requalify with --force "
+                "against current main before promotion"
+            ),
+        )
     branch = candidate_branch(target.pair)
     qualified_commit = target.harness.git_commit
     head = open_candidate_branches.get(branch)
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index 8c15ca83..c1fa015e 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -41,6 +41,7 @@
     core_requirement,
     latest_data_release,
     plan_promotion,
+    previous_certificate,
     read_replay,
     resolve_candidate,
     rewrite_certified_constants,
@@ -560,23 +561,31 @@ def test_acceptance_is_bound_to_the_receipt():
         )
 
 
+def _promotion_receipt(**kwargs):
+    return make_receipt(**kwargs).model_copy(
+        update={"previous_certificate": previous_certificate(BUNDLE)}
+    )
+
+
 def test_promotion_plan():
     current = (
         BUNDLE["data_releases"]["uk"]["model_package"]["version"],
         BUNDLE["data_releases"]["uk"]["data_package"]["version"],
         BUNDLE["packages"]["policyengine-core"]["version"],
     )
-    newest = make_receipt(
+    newest = _promotion_receipt(
         pair=make_pair(model="2.200.0", data=current[1], core=current[2])
     )
-    older = make_receipt(
+    older = _promotion_receipt(
         pair=make_pair(model="2.199.0", data=current[1], core=current[2])
     )
-    rejected = make_receipt(
+    rejected = _promotion_receipt(
         pair=make_pair(model="2.201.0", data=current[1], core=current[2]),
         gate_results=gates(replay="fail"),
     )
-    stale = make_receipt(pair=make_pair(model="2.0.0", data="1.0.0", core="3.0.0"))
+    stale = _promotion_receipt(
+        pair=make_pair(model="2.0.0", data="1.0.0", core="3.0.0")
+    )
     branches = {
         candidate_branch(r.pair): r.harness.git_commit
         for r in (newest, older, rejected, stale)
@@ -607,7 +616,7 @@ def test_pairs_that_share_versions_never_share_a_branch():
     assert qualified_pair.pair_id != other_core.pair_id
     assert candidate_branch(qualified_pair) != candidate_branch(other_core)
     assert qualified_pair.pair_id[:12] in candidate_branch(qualified_pair)
-    qualified = make_receipt(pair=qualified_pair)
+    qualified = _promotion_receipt(pair=qualified_pair)
     incomplete = make_receipt(pair=other_core, gate_results=gates(replay="unavailable"))
     plan = plan_promotion(
         [qualified, incomplete],
@@ -622,7 +631,7 @@ def test_pairs_that_share_versions_never_share_a_branch():
 def test_a_branch_that_moved_off_the_qualified_commit_is_not_promoted():
     """The replayed and tested commit must be the promoted commit."""
 
-    qualified = make_receipt(pair=_promotable_pair_and_branch())
+    qualified = _promotion_receipt(pair=_promotable_pair_and_branch())
     branch = candidate_branch(qualified.pair)
     plan = plan_promotion([qualified], BUNDLE, {branch: "f" * 40})
     assert plan.target == qualified and plan.ready_branch is None
@@ -635,7 +644,7 @@ def test_promote_readies_and_merges_only_the_qualified_commit(monkeypatch, tmp_p
     import argparse
     import importlib.util
 
-    qualified = make_receipt(pair=_promotable_pair_and_branch())
+    qualified = _promotion_receipt(pair=_promotable_pair_and_branch())
     branch = candidate_branch(qualified.pair)
     spec = importlib.util.spec_from_file_location(
         "check_uk_candidate_for_test",
@@ -662,6 +671,162 @@ def test_promote_readies_and_merges_only_the_qualified_commit(monkeypatch, tmp_p
     assert calls[1][-2:] == ["--match-head-commit", qualified.harness.git_commit]
 
 
+def test_promotion_requires_the_current_supported_years_baseline(monkeypatch):
+    """C passed against A, but loses the year B added before C finished."""
+
+    from policyengine.provenance.certification import (
+        BASIS_QUALIFIED_PAIR,
+        build_bundle_data_release_payload,
+        build_country_manifest_payload,
+    )
+    from policyengine.provenance.manifest import (
+        CountryReleaseManifest,
+        DataReleaseManifest,
+    )
+    from policyengine.provenance.uk_candidate import supported_years
+
+    core = BUNDLE["packages"]["policyengine-core"]["version"]
+    pair_b = make_pair(model="2.131.0", data="1.58.2", core=core)
+    pair_c = make_pair(model="2.132.0", data="1.58.3", core=core)
+    years_a = list(range(2025, 2032))
+    years_b = list(range(2025, 2033))
+    monkeypatch.setattr(
+        "policyengine.provenance.uk_candidate.data_year", lambda _: 2024
+    )
+
+    def gate(pair, years, previous_years):
+        return supported_years(
+            pair,
+            Path("projected.h5"),
+            required_years=years_a[:-1],
+            budget_horizon_years=years_a[1:],
+            previous_supported_years=previous_years,
+            projected_years=lambda _: years,
+        )[0]
+
+    gate_b = gate(pair_b, years_b, years_a)
+    gate_c = gate(pair_c, years_a, years_a)
+    assert gate_b.status == gate_c.status == "pass"
+    assert gate(pair_c, years_a, years_b).status == "fail"
+    receipt_b = _promotion_receipt(
+        pair=pair_b,
+        gate_results=[gate_b if g.gate_id == "supported_years" else g for g in gates()],
+    )
+    receipt_c = _promotion_receipt(
+        pair=pair_c,
+        gate_results=[gate_c if g.gate_id == "supported_years" else g for g in gates()],
+    )
+    assert receipt_b.promotable and receipt_c.promotable
+
+    release = json.loads(json.dumps(MANIFEST))
+    release["data_package"]["version"] = pair_b.data.release_version
+    release["build"]["build_id"] = pair_b.data.build_id
+    release["artifacts"][pair_b.data.dataset]["revision"] = pair_b.data.dataset_revision
+    manifest = DataReleaseManifest.model_validate(release)
+    uri_parts = {
+        "repo_id": pair_b.data.repo_id,
+        "repo_type": pair_b.data.repo_type,
+        "path": pair_b.data.release_manifest_path,
+        "revision": pair_b.data.release_manifest_revision,
+    }
+    country = build_country_manifest_payload(
+        country="uk",
+        manifest=manifest,
+        uri_parts=uri_parts,
+        policyengine_version=BUNDLE["policyengine_version"],
+        model_package=pair_b.model.name,
+        model_version=pair_b.model.version,
+        model_wheel={"sha256": pair_b.model.wheel_sha256},
+        compatibility_basis=BASIS_QUALIFIED_PAIR,
+        core_version=core,
+        qualified_pair_id=pair_b.pair_id,
+    )
+    record_b = build_bundle_data_release_payload(
+        country_payload=country,
+        data_producer="populace",
+        manifest_uri=f"hf://model/{pair_b.data.repo_id}@{pair_b.data.release_manifest_revision}/{pair_b.data.release_manifest_path}",
+        uri_parts=uri_parts,
+    )
+    CountryReleaseManifest.model_validate(record_b)
+    current_b = json.loads(json.dumps(BUNDLE))
+    current_b["data_releases"]["uk"] = record_b
+    branches = {candidate_branch(pair_c): receipt_c.harness.git_commit}
+
+    assert plan_promotion([receipt_b, receipt_c], BUNDLE, branches).ready_branch
+    plan = plan_promotion([receipt_b, receipt_c], current_b, branches)
+    assert plan.target == receipt_c
+    assert plan.ready_branch is None and plan.ready_commit is None
+    assert "requalif" in plan.reason and "--force" in plan.reason
+
+
+@pytest.mark.parametrize(
+    "field",
+    [None, *type(previous_certificate(BUNDLE)).model_fields],
+)
+def test_promotion_binds_every_previous_certificate_field(field):
+    qualified = _promotion_receipt(pair=_promotable_pair_and_branch())
+    previous = qualified.previous_certificate
+    if field is None:
+        previous = None
+    else:
+        value = getattr(previous, field)
+        if field in {"dataset_reference", "release_manifest_reference"}:
+            value = value.model_copy(update={"revision": "0" * 40})
+        elif field.endswith("sha256") or field == "qualification_pair_id":
+            value = "0" * 64
+        else:
+            value = "different"
+        previous = previous.model_copy(update={field: value})
+    stale = qualified.model_copy(update={"previous_certificate": previous})
+    plan = plan_promotion(
+        [stale], BUNDLE, {candidate_branch(stale.pair): stale.harness.git_commit}
+    )
+    assert plan.target == stale
+    assert plan.ready_branch is None and plan.ready_commit is None
+    assert "requalif" in plan.reason
+
+
+@pytest.mark.parametrize("missing", [False, True])
+def test_stale_baseline_does_not_close_or_fall_back_to_other_candidates(missing):
+    previous = previous_certificate(BUNDLE)
+    newest = _promotion_receipt(pair=_promotable_pair_and_branch()).model_copy(
+        update={
+            "previous_certificate": None
+            if missing
+            else previous.model_copy(update={"bundle_version": "different"})
+        }
+    )
+    older = _promotion_receipt(
+        pair=make_pair(
+            model="2.199.0",
+            data=newest.pair.data.release_version,
+            core=newest.pair.core.version,
+        )
+    )
+    superseded_by_main = _promotion_receipt(
+        pair=make_pair(model="2.0.0", data="1.0.0", core="3.0.0")
+    )
+    receipts = [newest, older, superseded_by_main]
+    branches = {candidate_branch(r.pair): r.harness.git_commit for r in receipts}
+    plan = plan_promotion(receipts, BUNDLE, branches)
+    assert plan.target == newest
+    assert plan.ready_branch is None and plan.ready_commit is None
+    assert plan.close_branches == [candidate_branch(superseded_by_main.pair)]
+
+
+def test_promotion_on_an_unrelated_main_commit_keeps_the_same_baseline():
+    qualified = _promotion_receipt(pair=_promotable_pair_and_branch())
+    unrelated_main = json.loads(json.dumps(BUNDLE))
+    unrelated_main["data_releases"]["us"]["data_package"]["version"] = "99.0.0"
+    assert previous_certificate(unrelated_main) == qualified.previous_certificate
+    branch = candidate_branch(qualified.pair)
+    plan = plan_promotion(
+        [qualified], unrelated_main, {branch: qualified.harness.git_commit}
+    )
+    assert plan.ready_branch == branch
+    assert plan.ready_commit == qualified.harness.git_commit
+
+
 def test_a_forced_rerun_stages_a_new_attempt(tmp_path):
     """Interrupted review of #574: a forced run reused the existing attempt key,
     so the workflow's duplicate guard stopped it."""
@@ -913,8 +1078,10 @@ def test_newer_abandoned_stage_recovers_despite_an_older_replay_request(tmp_path
 
 
 @pytest.mark.parametrize("verdict", ["qualified", "rejected"])
+@pytest.mark.parametrize("main_advanced", [False, True])
+@pytest.mark.parametrize("staged_base", ["a" * 40, "f" * 40])
 def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
-    tmp_path, verdict, monkeypatch, capsys
+    tmp_path, verdict, main_advanced, staged_base, monkeypatch, capsys
 ):
     import importlib.util
 
@@ -924,7 +1091,7 @@ def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
     pair = make_pair(model="2.200.0")
     results = gates(wheel_hashes="fail") if verdict == "rejected" else gates()
     terminal = make_receipt(pair=pair, gate_results=results)
-    base = "a" * 40
+    base = staged_base
     published = tmp_path / "uk" / pair.pair_id / "qualification_receipt.json"
     write_json(published, terminal.canonical_payload())
     attempt = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12] + "-2")
@@ -935,6 +1102,8 @@ def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
     stage_attempt(
         attempt, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
     )
+    if main_advanced:
+        base = "b" * 40
     now = "2026-10-14T15:00:00Z"
     assert (
         candidate_action(pair, BUNDLE, tmp_path, base_commit=base, now=now)[0]
@@ -960,8 +1129,59 @@ def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
     assert capsys.readouterr().out == ""
 
 
+@pytest.mark.parametrize("protected", ["live", "request", "terminal", "unbound"])
+def test_forced_recovery_preserves_newer_work_on_another_base(tmp_path, protected):
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import stage_attempt
+
+    pair = make_pair(model="2.200.0")
+    terminal = make_receipt(pair=pair)
+    write_json(
+        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
+        terminal.canonical_payload(),
+    )
+    original_base, replacement_base = "f" * 40, "b" * 40
+    payload = {
+        "pair": pair.canonical_payload(),
+        "supersedes_receipt_sha256": terminal.unreviewed_sha256,
+    }
+    original = attempt_directory(tmp_path, "uk", pair.pair_id, original_base[:12])
+    stage_attempt(
+        original, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
+    )
+    replacement = attempt_directory(tmp_path, "uk", pair.pair_id, replacement_base[:12])
+    replacement_payload = (
+        {"pair": pair.canonical_payload()} if protected == "unbound" else payload
+    )
+    stage_attempt(
+        replacement,
+        replacement_payload,
+        HARNESS,
+        owner_run_id="43",
+        staged_at=(
+            "2026-10-14T14:00:00Z" if protected == "live" else "2026-10-14T10:00:00Z"
+        ),
+    )
+    if protected == "request":
+        write_json(replacement / "replay" / "request.json", {"sent": True})
+    elif protected == "terminal":
+        write_json(
+            replacement / "qualification_receipt.json", terminal.canonical_payload()
+        )
+    for base in (original_base, replacement_base, "c" * 40):
+        assert (
+            candidate_action(
+                pair, BUNDLE, tmp_path, base_commit=base, now="2026-10-14T15:00:00Z"
+            )[0]
+            == "duplicate"
+        )
+
+
+@pytest.mark.parametrize("verdict", ["qualified", "rejected"])
+@pytest.mark.parametrize("main_advanced", [False, True])
+@pytest.mark.parametrize("abandonment", ["expired", "failed_owner"])
 def test_resolution_preserves_authorization_to_recover_forced_work(
-    tmp_path, monkeypatch
+    tmp_path, monkeypatch, verdict, main_advanced, abandonment
 ):
     import importlib.util
 
@@ -975,7 +1195,10 @@ def test_resolution_preserves_authorization_to_recover_forced_work(
     cli = importlib.util.module_from_spec(spec)
     spec.loader.exec_module(cli)
     pair = make_pair(model="2.200.0")
-    terminal = make_receipt(pair=pair, gate_results=gates(replay="fail"))
+    terminal = make_receipt(
+        pair=pair,
+        gate_results=gates(replay="fail") if verdict == "rejected" else gates(),
+    )
     write_json(
         tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
         terminal.canonical_payload(),
@@ -994,8 +1217,13 @@ def test_resolution_preserves_authorization_to_recover_forced_work(
     )
     monkeypatch.setattr(cli, "resolve_candidate", lambda **kwargs: resolved)
     monkeypatch.setattr(cli, "git", lambda *args: base)
-    monkeypatch.setattr(cli, "owner_run_failed", lambda _: False)
-    monkeypatch.setattr(cli, "utc_now", lambda: "2026-10-14T15:00:00Z")
+    monkeypatch.setattr(
+        cli,
+        "owner_run_failed",
+        lambda run_id: abandonment == "failed_owner" and run_id == "42",
+    )
+    now = "2026-10-14T15:00:00Z" if abandonment == "expired" else "2026-10-14T11:00:00Z"
+    monkeypatch.setattr(cli, "utc_now", lambda: now)
     monkeypatch.setattr(cli, "set_output", lambda **kwargs: None)
     out = tmp_path / "candidate.json"
     args = SimpleNamespace(
@@ -1012,12 +1240,61 @@ def test_resolution_preserves_authorization_to_recover_forced_work(
     stage_attempt(
         attempt, payload, HARNESS, owner_run_id="42", staged_at="2026-10-14T10:00:00Z"
     )
+    original_candidate = (attempt / "candidate.json").read_bytes()
+    if main_advanced:
+        base = "b" * 40
     args.force = False
     assert cli.cmd_resolve(args) == 0
     recovery = json.loads(out.read_text())
     assert recovery["action"] == "qualify"
-    assert recovery["attempt_key"] == base[:12] + "-2"
+    assert recovery["base_commit"] == base
+    assert recovery["attempt_key"] == (base[:12] if main_advanced else base[:12] + "-2")
     assert recovery["supersedes_receipt_sha256"] == terminal.unreviewed_sha256
+    replacement = attempt_directory(
+        tmp_path, "uk", pair.pair_id, recovery["attempt_key"]
+    )
+    stage_attempt(replacement, recovery, HARNESS, owner_run_id="43", staged_at=now)
+    assert (attempt / "candidate.json").read_bytes() == original_candidate
+    assert cli.cmd_resolve(args) == 0
+    assert json.loads(out.read_text())["action"] == "duplicate"
+
+
+def test_cross_base_recovery_allocates_new_keys_without_overwriting_evidence(tmp_path):
+    from policyengine.provenance.qualification_ledger import attempt_directory
+    from policyengine.provenance.uk_qualification import attempt_key, stage_attempt
+
+    pair = make_pair(model="2.200.0")
+    old_base, current_base = "a" * 40, "b" * 40
+    existing = attempt_directory(tmp_path, "uk", pair.pair_id, current_base[:12])
+    sent_payload = {"pair": pair.canonical_payload(), "base_commit": current_base}
+    stage_attempt(
+        existing,
+        sent_payload,
+        HARNESS,
+        owner_run_id="41",
+        staged_at="2026-10-14T09:00:00Z",
+    )
+    write_json(existing / "replay" / "request.json", {"sent": True})
+    abandoned = attempt_directory(tmp_path, "uk", pair.pair_id, old_base[:12])
+    stage_attempt(
+        abandoned,
+        {"pair": pair.canonical_payload(), "base_commit": old_base},
+        HARNESS,
+        owner_run_id="42",
+        staged_at="2026-10-14T10:00:00Z",
+    )
+    now = "2026-10-14T15:00:00Z"
+    assert (
+        candidate_action(pair, BUNDLE, tmp_path, base_commit=current_base, now=now)[0]
+        == "qualify"
+    )
+    assert attempt_key(pair, tmp_path, base_commit=current_base, now=now) == (
+        current_base[:12] + "-2"
+    )
+    assert json.loads((existing / "candidate.json").read_text()) == sent_payload
+    assert json.loads((existing / "replay" / "request.json").read_text()) == {
+        "sent": True
+    }
 
 
 @pytest.mark.parametrize(
diff --git a/tests/test_uk_qualification_workflow.py b/tests/test_uk_qualification_workflow.py
index 896cda51..ad81326b 100644
--- a/tests/test_uk_qualification_workflow.py
+++ b/tests/test_uk_qualification_workflow.py
@@ -14,7 +14,11 @@
 import pytest
 import yaml
 
-from policyengine.provenance.uk_qualification import accept_review, candidate_branch
+from policyengine.provenance.uk_qualification import (
+    accept_review,
+    candidate_branch,
+    previous_certificate,
+)
 from tests.qualification_fixtures import gates, make_pair, make_receipt
 
 REPO_ROOT = Path(__file__).resolve().parents[1]
@@ -67,7 +71,7 @@ def test_head_replacement_and_readiness_share_one_serialization(
             data=bundle["data_releases"]["uk"]["data_package"]["version"],
             core=bundle["packages"]["policyengine-core"]["version"],
         )
-    )
+    ).model_copy(update={"previous_certificate": previous_certificate(bundle)})
     branch = candidate_branch(qualified.pair)
     state_path = tmp_path / "state.json"
     state_path.write_text(

From 00b4cfeb1461a6eb3c5cee1f4a1c7e5eba54fde5 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Thu, 15 Oct 2026 09:42:12 -0400
Subject: [PATCH 32/45] Never let a concurrent ledger publish merge two
 attempts' receipts

Round-6 review of #574 (first attempt) found that two attempts of one
pair both write the pair's published files, and the publish script's
retry cherry-picked one onto the other. Git merged the indented JSON
receipts line by line into a valid-looking receipt that was neither
attempt's: the newer attempt's harness with the older attempt's passing
replay. Promotion then readied a commit whose replay never ran.

- The publish script replays a pair's published files
  (qualification_receipt.json, latest_attempt.json, pair.json) as binary,
  so a concurrent change to them conflicts. If those are the only
  conflicts and LEDGER_REDERIVE is set, it keeps the tip's copies and
  recomputes every pair's published files from its immutable attempts;
  otherwise the publish fails. The workflow sets LEDGER_REDERIVE to the
  new `rederive-ledger` command.
- Readers trust a published receipt only if it is the current receipt of
  the pair's latest-staged attempt (a review acceptance aside):
  latest_receipts leaves other pairs out and reports why, promotion
  prints them, resolve, recoverable and accept refuse them, and
  fetch_ledger_receipt checks the attempt latest_attempt.json names.
- Tests reproduce the race with the real script and git in both orders,
  with and without the hook, and refuse a hand-made merged receipt in
  every reader. Each mutant of the fix fails them.

Co-Authored-By: Claude Opus 5.5 
---
 .github/qualification-ledger.sh               |  56 ++-
 .github/workflows/certify-uk-release.yaml     |   6 +
 scripts/check_uk_candidate.py                 |  51 +-
 .../provenance/qualification_ledger.py        | 176 ++++++-
 .../test_qualification_ledger_concurrency.py  | 459 ++++++++++++++++++
 tests/test_qualified_pair_certification.py    |   5 +-
 tests/test_uk_qualification_pipeline.py       |  27 +-
 tests/test_uk_qualification_workflow.py       |   4 +-
 8 files changed, 741 insertions(+), 43 deletions(-)
 create mode 100644 tests/test_qualification_ledger_concurrency.py

diff --git a/.github/qualification-ledger.sh b/.github/qualification-ledger.sh
index b42186d6..5906ce64 100755
--- a/.github/qualification-ledger.sh
+++ b/.github/qualification-ledger.sh
@@ -5,11 +5,20 @@
 #   .github/qualification-ledger.sh checkout 
 #   .github/qualification-ledger.sh publish  ""
 #
-# The ledger is an orphan branch that only grows: each candidate pair writes
-# its own directory, so concurrent publishes never touch the same file and a
-# rejected push is retried by replaying the single new commit on the latest
-# tip. The new commit may be the branch's first (two runs can both find no
-# ledger yet), so it is replayed with cherry-pick, which needs no parent.
+# The ledger is an orphan branch that only grows. Each attempt writes its own
+# directory (uk//attempts//), which concurrent publishes never
+# share. A rejected push is retried by replaying the single new commit on the
+# latest tip; the new commit may be the branch's first (two runs can both find
+# no ledger yet), so it is replayed with cherry-pick, which needs no parent.
+#
+# Two attempts of one pair do share that pair's published files
+# (qualification_receipt.json, latest_attempt.json and pair.json). Git must
+# never merge those line by line: a textual merge of two receipts can produce
+# a valid-looking receipt that is neither (one attempt's harness with another's
+# replay). They are replayed as binary, so a concurrent change to them
+# conflicts. When those are the only conflicts and LEDGER_REDERIVE is set, the
+# tip's copies are kept and "$LEDGER_REDERIVE " recomputes every pair's
+# published files from its immutable attempts; otherwise the publish fails.
 set -euo pipefail
 
 BRANCH="${LEDGER_BRANCH:-uk-qualification-ledger}"
@@ -50,6 +59,12 @@ README
     git "${identity[@]}" commit --quiet -m "$message"
     new_commit="$(git rev-parse HEAD)"
     delay="${LEDGER_RETRY_DELAY:-5}"
+    attributes="$(mktemp)"
+    trap 'rm -f "$attributes"' EXIT
+    printf '%s\n' \
+      'qualification_receipt.json merge=binary' \
+      'latest_attempt.json merge=binary' \
+      'pair.json merge=binary' > "$attributes"
     for attempt in 1 2 3 4 5 6; do
       if git push --quiet origin "HEAD:refs/heads/$BRANCH"; then
         echo "Published ledger: $message"
@@ -61,10 +76,33 @@ README
         continue
       fi
       git reset --quiet --hard FETCH_HEAD
-      if ! git "${identity[@]}" cherry-pick --allow-empty "$new_commit" >/dev/null; then
-        git cherry-pick --abort || true
-        echo "::error::The ledger commit conflicts with a concurrent publish."
-        exit 1
+      if ! git "${identity[@]}" -c core.attributesFile="$attributes" \
+          cherry-pick --allow-empty "$new_commit" >/dev/null 2>&1; then
+        conflicted="$(git diff --name-only --diff-filter=U)"
+        shared_only=true
+        while IFS= read -r path; do
+          [ -z "$path" ] && continue
+          case "$path" in
+            uk/*/qualification_receipt.json|uk/*/latest_attempt.json|uk/*/pair.json)
+              # Only a pair's published files, never an attempt's own.
+              case "$path" in uk/*/*/*) shared_only=false ;; esac ;;
+            *) shared_only=false ;;
+          esac
+        done <<< "$conflicted"
+        if [ -z "$conflicted" ] || [ "$shared_only" != true ] \
+            || [ -z "${LEDGER_REDERIVE:-}" ]; then
+          git cherry-pick --abort || true
+          echo "::error::The ledger commit conflicts with a concurrent publish."
+          exit 1
+        fi
+        while IFS= read -r path; do
+          git checkout --ours -- "$path"
+        done <<< "$conflicted"
+        # Recompute published files from the attempts, the tip's and this one's.
+        $LEDGER_REDERIVE "$PWD"
+        git add -A
+        # Completes the cherry-pick, keeping its message, even if empty.
+        git "${identity[@]}" commit --quiet --allow-empty --no-edit
       fi
       sleep $((attempt * delay))
     done
diff --git a/.github/workflows/certify-uk-release.yaml b/.github/workflows/certify-uk-release.yaml
index d48946d9..6d2c6277 100644
--- a/.github/workflows/certify-uk-release.yaml
+++ b/.github/workflows/certify-uk-release.yaml
@@ -51,6 +51,12 @@ env:
   LEDGER_BRANCH: uk-qualification-ledger
   UV_VERSION: "0.12.14"
   PYTHON_VERSION: "3.13"
+  # Run by .github/qualification-ledger.sh, inside the ledger worktree, when a
+  # concurrent publish touched a pair's published files: recompute them from
+  # the attempts rather than let git merge two receipts.
+  LEDGER_REDERIVE: >-
+    uv run --project ${{ github.workspace }} python
+    ${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger
 
 jobs:
   resolve:
diff --git a/scripts/check_uk_candidate.py b/scripts/check_uk_candidate.py
index 9a5ac8eb..e8824681 100644
--- a/scripts/check_uk_candidate.py
+++ b/scripts/check_uk_candidate.py
@@ -48,16 +48,18 @@
     CandidatePair,
     IssuedBy,
     QualificationHarness,
-    QualificationReceipt,
     ReplayQualificationRequest,
 )
 from policyengine.provenance.qualification_ledger import (  # noqa: E402
     LEDGER_BRANCH,
     LEDGER_REPOSITORY,
+    LedgerInconsistency,
     attempt_directory,
     latest_receipts,
     pair_directory,
+    published_receipt,
     read_json,
+    rederive_publication,
     write_json,
 )
 from policyengine.provenance.uk_qualification import (  # noqa: E402
@@ -249,12 +251,9 @@ def cmd_resolve(args: argparse.Namespace) -> int:
         "previous_certificate": previous_certificate(bundle).canonical_payload(),
     }
     if action == "qualify" and args.ledger:
-        published = (
-            pair_directory(Path(args.ledger), "uk", resolved.pair.pair_id)
-            / "qualification_receipt.json"
-        )
-        if published.exists():
-            receipt = QualificationReceipt.model_validate(read_json(published))
+        pair_dir = pair_directory(Path(args.ledger), "uk", resolved.pair.pair_id)
+        if (pair_dir / "qualification_receipt.json").exists():
+            receipt = published_receipt(pair_dir)
             if receipt.verdict != "incomplete":
                 # Forced work, or recovery of work already bound to this receipt.
                 payload["supersedes_receipt_sha256"] = receipt.unreviewed_sha256
@@ -480,7 +479,11 @@ def cmd_recoverable(args: argparse.Namespace) -> int:
             continue
         attempt = max(stages, key=lambda path: int(read_json(path)["sequence"])).parent
         if receipt.exists():
-            terminal = QualificationReceipt.model_validate(read_json(receipt))
+            try:
+                terminal = published_receipt(pair_dir)
+            except LedgerInconsistency as error:
+                print(f"::warning::{error}", file=sys.stderr)
+                continue
             if terminal.verdict != "incomplete" and not attempt_supersedes_receipt(
                 attempt, terminal
             ):
@@ -568,7 +571,11 @@ def cmd_refresh_pr_checks(args: argparse.Namespace) -> int:
 
 def cmd_promote(args: argparse.Namespace) -> int:
     bundle = json.loads(BUNDLE_PATH.read_text())
-    receipts = latest_receipts(Path(args.ledger))
+    problems: list[str] = []
+    receipts = latest_receipts(Path(args.ledger), problems=problems)
+    for problem in problems:
+        # Such a pair is left out of the plan until its files are rederived.
+        print(f"::warning::{problem}")
     branches = _open_candidate_branches() if args.apply else {}
     plan = plan_promotion(receipts, bundle, branches)
     print(f"promotion: {plan.reason}")
@@ -622,11 +629,10 @@ def cmd_promote(args: argparse.Namespace) -> int:
 
 
 def cmd_accept(args: argparse.Namespace) -> int:
-    path = (
-        pair_directory(Path(args.ledger), "uk", args.pair_id)
-        / "qualification_receipt.json"
-    )
-    receipt = QualificationReceipt.model_validate(read_json(path))
+    pair_dir = pair_directory(Path(args.ledger), "uk", args.pair_id)
+    path = pair_dir / "qualification_receipt.json"
+    # Accept only a receipt that is an attempt's own, never a merged one.
+    receipt = published_receipt(pair_dir)
     reviewed = accept_review(
         receipt,
         reviewer=args.reviewer or os.environ.get("GITHUB_ACTOR", ""),
@@ -715,9 +721,26 @@ def parser() -> argparse.ArgumentParser:
     accept.add_argument("--explanation", required=True)
     accept.add_argument("--reviewer")
     accept.set_defaults(func=cmd_accept)
+
+    rederive = commands.add_parser("rederive-ledger")
+    rederive.add_argument("ledger")
+    rederive.set_defaults(func=cmd_rederive_ledger)
     return parser
 
 
+def cmd_rederive_ledger(args: argparse.Namespace) -> int:
+    """Recompute every pair's published files from its attempts.
+
+    Called by .github/qualification-ledger.sh after a concurrent publish
+    changed a pair's published files on both sides.
+    """
+
+    for pair_dir in sorted((Path(args.ledger) / "uk").glob("*")):
+        if pair_dir.is_dir():
+            rederive_publication(pair_dir)
+    return 0
+
+
 def main(argv: Optional[list[str]] = None) -> int:
     args = parser().parse_args(argv)
     return int(args.func(args) or 0)
diff --git a/src/policyengine/provenance/qualification_ledger.py b/src/policyengine/provenance/qualification_ledger.py
index d38d2a63..cb1aa6b6 100644
--- a/src/policyengine/provenance/qualification_ledger.py
+++ b/src/policyengine/provenance/qualification_ledger.py
@@ -7,6 +7,7 @@
     //
         pair.json                       the CandidatePair
         qualification_receipt.json      the latest terminal receipt for the pair
+        latest_attempt.json             which attempt that receipt came from
         attempts//
             harness.json                the candidate commit that ran it
             gates/.json        each gate's evidence
@@ -16,6 +17,10 @@
             qualification_receipt.json  this attempt's receipt
 
 Failed and incomplete attempts are kept: the ledger never deletes evidence.
+A pair's published files are derived from its attempts and are trusted only
+when the published receipt is one attempt's own receipt
+(:func:`published_receipt`): concurrent publishes must never yield a receipt
+that mixes two attempts.
 A bundle certificate with basis ``qualified_exact_pair`` must point at a pair
 whose latest receipt is promotable and matches the certificate exactly
 (:func:`verify_certification_evidence`).
@@ -39,16 +44,24 @@
 __all__ = [
     "LEDGER_BRANCH",
     "LEDGER_REPOSITORY",
+    "LedgerInconsistency",
     "attempt_directory",
     "fetch_ledger_receipt",
     "latest_receipts",
     "pair_directory",
     "pending_attempts",
+    "latest_attempt_receipt",
+    "published_receipt",
+    "rederive_publication",
     "verify_certification_evidence",
     "write_json",
 ]
 
 
+class LedgerInconsistency(ValueError):
+    """A pair's published receipt is not any one attempt's receipt."""
+
+
 def write_json(path: Path, value: Any) -> None:
     """Write readable, deterministic JSON (digests are over the JSON value)."""
 
@@ -75,15 +88,133 @@ def attempt_directory(
     return pair_directory(root, country_id, pair_id) / "attempts" / attempt_key
 
 
-def latest_receipts(root: Path, country_id: str = "uk") -> list[QualificationReceipt]:
-    """Every pair's latest terminal receipt in a checked-out ledger."""
+def _matches_an_attempt(
+    receipt: QualificationReceipt, attempt_receipts: Iterable[QualificationReceipt]
+) -> bool:
+    """Whether ``receipt`` is one attempt's receipt, a review acceptance aside.
+
+    ``unreviewed_sha256`` covers every field but ``review``, so a receipt that
+    joins one attempt's harness to another's replay or gates matches neither.
+    """
+
+    return any(
+        attempt.unreviewed_sha256 == receipt.unreviewed_sha256
+        for attempt in attempt_receipts
+    )
+
+
+def latest_attempt_receipt(
+    pair_dir: Path,
+) -> Optional[tuple[str, int, QualificationReceipt]]:
+    """The receipt a pair publishes: its latest-staged attempt's current receipt.
+
+    Attempts are ordered by the ``sequence`` in their ``staging.json`` (0 when
+    absent); an attempt without a receipt yet does not count. Returns the
+    attempt key, its sequence and its receipt, or None if no attempt has one.
+    """
+
+    latest: Optional[tuple[int, str, Path]] = None
+    for path in pair_dir.glob("attempts/*/qualification_receipt.json"):
+        stage = path.parent / "staging.json"
+        sequence = int(read_json(stage)["sequence"]) if stage.exists() else 0
+        candidate = (sequence, path.parent.name, path)
+        if latest is None or candidate[:2] > latest[:2]:
+            latest = candidate
+    if latest is None:
+        return None
+    sequence, key, path = latest
+    return key, sequence, QualificationReceipt.model_validate(read_json(path))
+
+
+def published_receipt(pair_dir: Path) -> QualificationReceipt:
+    """A pair's published receipt, verified against the attempts it derives from.
+
+    It must be the current receipt of the pair's latest-staged attempt
+    (:func:`latest_attempt_receipt`), up to a review acceptance, which is added
+    afterwards. Raises :class:`LedgerInconsistency` otherwise, for instance
+    after a textual merge of two attempts' receipts.
+    """
+
+    receipt = QualificationReceipt.model_validate(
+        read_json(pair_dir / "qualification_receipt.json")
+    )
+    latest = latest_attempt_receipt(pair_dir)
+    if latest is None:
+        raise LedgerInconsistency(
+            f"{pair_dir.name}: a qualification receipt is published but no "
+            "attempt has one"
+        )
+    key, _, attempt = latest
+    if not _matches_an_attempt(receipt, [attempt]):
+        raise LedgerInconsistency(
+            f"{pair_dir.name}: the published qualification receipt "
+            f"({receipt.unreviewed_sha256}) is not the receipt of attempt {key}, "
+            "the latest staged"
+        )
+    return receipt
+
+
+def rederive_publication(pair_dir: Path) -> Optional[QualificationReceipt]:
+    """Rewrite a pair's published files from its attempts.
+
+    Writes ``qualification_receipt.json`` (the latest-staged attempt's
+    receipt), ``latest_attempt.json`` and ``pair.json``. A review acceptance of
+    exactly that receipt is kept, from the published receipt if it validates or
+    from ``reviews/``, the latest acceptance first. Used after a concurrent
+    publish, so that git never decides these files by merging two attempts.
+    """
+
+    latest = latest_attempt_receipt(pair_dir)
+    if latest is None:
+        return None
+    key, sequence, receipt = latest
+    published = pair_dir / "qualification_receipt.json"
+    accepted: list[QualificationReceipt] = []
+    for source in [published, *sorted(pair_dir.glob("reviews/*.json"))]:
+        if not source.exists():
+            continue
+        try:
+            candidate = QualificationReceipt.model_validate(read_json(source))
+        except ValueError:
+            continue
+        if (
+            candidate.review is not None
+            and candidate.promotable
+            and candidate.unreviewed_sha256 == receipt.unreviewed_sha256
+        ):
+            accepted.append(candidate)
+    if accepted:
+        receipt = max(accepted, key=lambda item: item.review.accepted_at)
+    write_json(published, receipt.canonical_payload())
+    write_json(
+        pair_dir / "latest_attempt.json", {"attempt_key": key, "sequence": sequence}
+    )
+    write_json(pair_dir / "pair.json", receipt.pair.canonical_payload())
+    return receipt
+
+
+def latest_receipts(
+    root: Path,
+    country_id: str = "uk",
+    *,
+    problems: Optional[list[str]] = None,
+) -> list[QualificationReceipt]:
+    """Every pair's latest terminal receipt in a checked-out ledger.
+
+    A pair whose published receipt is not one of its attempts' receipts is
+    left out, and the reason is appended to ``problems`` when given.
+    """
 
     base = root / country_id
     if not base.is_dir():
         return []
     receipts = []
     for path in sorted(base.glob("*/qualification_receipt.json")):
-        receipts.append(QualificationReceipt.model_validate(read_json(path)))
+        try:
+            receipts.append(published_receipt(path.parent))
+        except LedgerInconsistency as error:
+            if problems is not None:
+                problems.append(str(error))
     return receipts
 
 
@@ -106,20 +237,47 @@ def fetch_ledger_receipt(
     *,
     get: Optional[Callable[..., Any]] = None,
 ) -> Optional[QualificationReceipt]:
-    """Read a pair's latest receipt from the published ledger branch."""
+    """Read a pair's latest receipt from the published ledger branch.
+
+    The receipt must be the receipt of the attempt ``latest_attempt.json``
+    names (a review acceptance aside), as :func:`published_receipt` requires
+    of a checked-out ledger; otherwise :class:`LedgerInconsistency` is raised.
+    """
 
     if get is None:
         import requests
 
         get = requests.get
-    response = get(
-        f"{RAW_LEDGER_URL}/{country_id}/{pair_id}/qualification_receipt.json",
-        timeout=30,
-    )
+    base = f"{RAW_LEDGER_URL}/{country_id}/{pair_id}"
+    response = get(f"{base}/qualification_receipt.json", timeout=30)
     if response.status_code == 404:
         return None
     response.raise_for_status()
-    return QualificationReceipt.model_validate_json(response.text)
+    receipt = QualificationReceipt.model_validate_json(response.text)
+    pointer_response = get(f"{base}/latest_attempt.json", timeout=30)
+    if pointer_response.status_code == 404:
+        raise LedgerInconsistency(
+            f"{pair_id}: the published receipt names no attempt (no latest_attempt.json)"
+        )
+    pointer_response.raise_for_status()
+    attempt_key = json.loads(pointer_response.text).get("attempt_key")
+    if not isinstance(attempt_key, str) or not attempt_key or "/" in attempt_key:
+        raise LedgerInconsistency(f"{pair_id}: latest_attempt.json is malformed")
+    attempt_response = get(
+        f"{base}/attempts/{attempt_key}/qualification_receipt.json", timeout=30
+    )
+    if attempt_response.status_code == 404:
+        raise LedgerInconsistency(
+            f"{pair_id}: attempt {attempt_key} has no qualification receipt"
+        )
+    attempt_response.raise_for_status()
+    attempt = QualificationReceipt.model_validate_json(attempt_response.text)
+    if not _matches_an_attempt(receipt, [attempt]):
+        raise LedgerInconsistency(
+            f"{pair_id}: the published qualification receipt is not attempt "
+            f"{attempt_key}'s receipt"
+        )
+    return receipt
 
 
 def verify_certification_evidence(
diff --git a/tests/test_qualification_ledger_concurrency.py b/tests/test_qualification_ledger_concurrency.py
new file mode 100644
index 00000000..efb1f143
--- /dev/null
+++ b/tests/test_qualification_ledger_concurrency.py
@@ -0,0 +1,459 @@
+"""Concurrent publishes never yield a receipt that mixes two attempts.
+
+Round-6 review of #574: two attempts of one pair both write the pair's
+published files. When the older attempt's replay finished after the newer
+attempt had published, the publish script's cherry-pick merged the two
+indented JSON receipts line by line into a valid-looking receipt: the newer
+attempt's harness with the older attempt's passing replay. Promotion then
+readied a commit whose replay never ran.
+
+Invariants:
+
+- after any interleaving of two publishes, the pair's published receipt is
+  the current receipt of its latest-staged attempt, and every attempt's
+  evidence is on the branch;
+- without a rederive hook the publish fails rather than merging receipts;
+- a published receipt that is not its latest attempt's own is refused by
+  every reader (listing, promotion, acceptance, remote fetch).
+"""
+
+from __future__ import annotations
+
+import json
+import os
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+from types import SimpleNamespace
+
+import pytest
+
+from policyengine.provenance.canonical import canonical_sha256
+from policyengine.provenance.qualification import (
+    QualificationReceipt,
+    ReplayReceipt,
+    ReplayStatus,
+    evaluate_replay_receipt,
+)
+from policyengine.provenance.qualification_ledger import (
+    LedgerInconsistency,
+    fetch_ledger_receipt,
+    latest_receipts,
+    published_receipt,
+    read_json,
+    rederive_publication,
+    write_json,
+)
+from policyengine.provenance.uk_qualification import (
+    accept_review,
+    build_replay_request,
+    candidate_branch,
+    finalize_attempt,
+    plan_promotion,
+    previous_certificate,
+    stage_attempt,
+    write_gate_results,
+)
+from tests.qualification_fixtures import HARNESS, ISSUED, gates, golden, make_pair
+
+ROOT = Path(__file__).resolve().parents[1]
+SCRIPT = ROOT / ".github" / "qualification-ledger.sh"
+CLI = ROOT / "scripts" / "check_uk_candidate.py"
+BASE = json.loads(
+    (ROOT / "src" / "policyengine" / "data" / "bundle" / "manifest.json").read_text()
+)
+PAIR = make_pair(
+    model="2.200.0", data=BASE["data_releases"]["uk"]["data_package"]["version"]
+)
+NEWER_HARNESS = HARNESS.model_copy(
+    update={"git_commit": "b" * 40, "packaged_bundle_manifest_sha256": "8" * 64}
+)
+REDERIVE = f"{sys.executable} {CLI} rederive-ledger"
+
+pytestmark = pytest.mark.skipif(shutil.which("git") is None, reason="needs git")
+
+
+def _run(*args, cwd, check=True, rederive=None):
+    env = {
+        **os.environ,
+        "GIT_AUTHOR_NAME": "test",
+        "GIT_AUTHOR_EMAIL": "test@example.org",
+        "GIT_COMMITTER_NAME": "test",
+        "GIT_COMMITTER_EMAIL": "test@example.org",
+        "GIT_TERMINAL_PROMPT": "0",
+        "LEDGER_RETRY_DELAY": "0",
+        "POLICYENGINE_SKIP_COUNTRY_IMPORTS": "1",
+        "PYTHONPATH": str(ROOT / "src") + os.pathsep + str(ROOT),
+    }
+    env.pop("LEDGER_REDERIVE", None)
+    if rederive is not None:
+        env["LEDGER_REDERIVE"] = rederive
+    return subprocess.run(
+        args,
+        cwd=cwd,
+        env=env,
+        check=check,
+        text=True,
+        stdout=subprocess.PIPE,
+        stderr=subprocess.STDOUT,
+    )
+
+
+def _request(harness):
+    return build_replay_request(
+        PAIR,
+        harness,
+        release_bundle=golden("qualification_request_golden")["candidate"][
+            "expected_release_bundle"
+        ],
+        issued_by=ISSUED,
+    )
+
+
+def _complete_replay(attempt: Path, request) -> None:
+    """Write a passing replay for ``request`` into ``attempt``."""
+
+    document = golden("replay_receipt_golden")
+    document["request_id"] = request.request_id
+    execution = document["execution"]
+    execution["packaged_bundle_manifest_sha256"] = (
+        request.candidate.policyengine.packaged_bundle_manifest_sha256
+    )
+    execution["dataset_sha256"] = PAIR.data.dataset_sha256
+    execution["release_bundle"] = request.candidate.expected_release_bundle
+    execution["packages"]["policyengine"]["version"] = (
+        request.candidate.policyengine.version
+    )
+    for key, package in (
+        ("policyengine-uk", PAIR.model),
+        ("policyengine-core", PAIR.core),
+    ):
+        execution["packages"][key]["version"] = package.version
+        execution["packages"][key]["wheel_sha256"] = package.wheel_sha256
+    document["diff"]["flag_counts"] = {
+        key: 0 for key in document["diff"]["flag_counts"]
+    }
+    document["diff"]["flagged_rows"] = []
+    document["receipt_sha256"] = canonical_sha256(
+        {key: value for key, value in document.items() if key != "receipt_sha256"}
+    )
+    receipt = ReplayReceipt.from_document(document)
+    status = ReplayStatus.model_validate(
+        {
+            "schema": "policyengine.uk-replay-status/v1",
+            "request_id": request.request_id,
+            "status": "complete",
+            "receipt_sha256": receipt.receipt_sha256,
+            "receipt_commit": "c" * 40,
+            "history": [
+                {
+                    "status": "complete",
+                    "at": "2026-10-15T10:00:00Z",
+                    "run_url": "https://github.com/PolicyEngine/policyengine-scorecard/actions/runs/7",
+                }
+            ],
+        }
+    )
+    gate = evaluate_replay_receipt(request, status, receipt)
+    assert gate.status == "pass", gate
+    write_json(attempt / "replay" / "request.json", request.document())
+    write_json(attempt / "replay" / "status.json", status.document())
+    write_json(attempt / "replay" / "receipt.json", receipt.document())
+    write_json(attempt / "replay" / "replay.result.json", gate.canonical_payload())
+
+
+def _stage(attempt: Path, harness, owner: str, staged_at: str) -> None:
+    payload = {
+        "pair": PAIR.canonical_payload(),
+        "previous_certificate": previous_certificate(BASE).canonical_payload(),
+        "branch": candidate_branch(PAIR),
+    }
+    stage_attempt(attempt, payload, harness, owner_run_id=owner, staged_at=staged_at)
+    write_gate_results(attempt, [g for g in gates() if g.gate_id != "replay"], {})
+
+
+def _origin(root: Path) -> Path:
+    origin = root / "origin.git"
+    _run("git", "init", "--quiet", "--bare", "-b", "main", str(origin), cwd=root)
+    seed = root / "seed"
+    _run("git", "clone", "--quiet", str(origin), str(seed), cwd=root)
+    (seed / "seed").write_text("seed")
+    _run("git", "add", "seed", cwd=seed)
+    _run("git", "commit", "--quiet", "-m", "seed", cwd=seed)
+    _run("git", "push", "--quiet", "origin", "HEAD:refs/heads/main", cwd=seed)
+    return origin
+
+
+def _ledger_clone(root: Path, origin: Path, name: str) -> Path:
+    clone = root / name
+    _run(
+        "git", "clone", "--quiet", "--branch", "main", str(origin), str(clone), cwd=root
+    )
+    _run("bash", str(SCRIPT), "checkout", "ledger", cwd=clone)
+    return clone
+
+
+def _published(origin: Path, path: str) -> dict:
+    shown = _run(
+        "git", "show", f"uk-qualification-ledger:uk/{PAIR.pair_id}/{path}", cwd=origin
+    )
+    return json.loads(shown.stdout)
+
+
+def _race(tmp_path: Path, *, older_publishes_last: bool, rederive):
+    """Attempt A (older) and B (newer) of one pair publish concurrently.
+
+    A is staged and published first. Each run then works in its own clone:
+    B finalizes incomplete; A's replay completes and it finalizes qualified.
+    """
+
+    origin = _origin(tmp_path)
+    seed = _ledger_clone(tmp_path, origin, "seed-ledger")
+    pair_dir = seed / "ledger" / "uk" / PAIR.pair_id
+    _stage(pair_dir / "attempts" / "a", HARNESS, "1", "2026-10-15T09:00:00Z")
+    finalize_attempt(
+        pair_dir / "attempts" / "a",
+        seed / "ledger",
+        issued_by=ISSUED,
+        completed_at="2026-10-15T09:30:00Z",
+    )
+    _run("bash", str(SCRIPT), "publish", "ledger", "A incomplete", cwd=seed)
+
+    clone_a = _ledger_clone(tmp_path, origin, "a")
+    clone_b = _ledger_clone(tmp_path, origin, "b")
+    attempt_a = clone_a / "ledger" / "uk" / PAIR.pair_id / "attempts" / "a"
+    attempt_b = clone_b / "ledger" / "uk" / PAIR.pair_id / "attempts" / "b"
+    _stage(attempt_b, NEWER_HARNESS, "2", "2026-10-15T10:01:00Z")
+    receipt_b = finalize_attempt(
+        attempt_b,
+        clone_b / "ledger",
+        issued_by=ISSUED.model_copy(update={"workflow_run_id": 2}),
+        completed_at="2026-10-15T10:02:00Z",
+    )
+    assert receipt_b.verdict == "incomplete"
+    _complete_replay(attempt_a, _request(HARNESS))
+    receipt_a = finalize_attempt(
+        attempt_a,
+        clone_a / "ledger",
+        issued_by=ISSUED,
+        completed_at="2026-10-15T10:02:00Z",
+    )
+    assert receipt_a.verdict == "qualified"
+
+    order = [(clone_b, "B"), (clone_a, "A")]
+    if not older_publishes_last:
+        order.reverse()
+    first, second = order
+    _run("bash", str(SCRIPT), "publish", "ledger", f"{first[1]}", cwd=first[0])
+    result = _run(
+        "bash",
+        str(SCRIPT),
+        "publish",
+        "ledger",
+        f"{second[1]}",
+        cwd=second[0],
+        check=False,
+        rederive=rederive,
+    )
+    return origin, result, receipt_a, receipt_b
+
+
+@pytest.mark.parametrize("older_publishes_last", [True, False])
+def test_concurrent_attempts_publish_the_latest_attempts_receipt(
+    tmp_path, older_publishes_last
+):
+    origin, result, receipt_a, receipt_b = _race(
+        tmp_path, older_publishes_last=older_publishes_last, rederive=REDERIVE
+    )
+    assert result.returncode == 0, result.stdout
+    published = QualificationReceipt.model_validate(
+        _published(origin, "qualification_receipt.json")
+    )
+    # B was staged last, so B's receipt is published, whichever came last.
+    assert published.unreviewed_sha256 == receipt_b.unreviewed_sha256
+    assert published.harness.git_commit == "b" * 40
+    assert _published(origin, "latest_attempt.json")["attempt_key"] == "b"
+    files = _run(
+        "git", "ls-tree", "-r", "--name-only", "uk-qualification-ledger", cwd=origin
+    ).stdout.split()
+    for key in ("a", "b"):
+        assert f"uk/{PAIR.pair_id}/attempts/{key}/qualification_receipt.json" in files
+    # Nothing qualified is published for B, so B's commit is never readied.
+    plan = plan_promotion([published], BASE, {candidate_branch(PAIR): "b" * 40})
+    assert plan.ready_commit is None
+
+
+def test_without_a_rederive_hook_the_publish_fails_rather_than_merging(tmp_path):
+    origin, result, _, receipt_b = _race(
+        tmp_path, older_publishes_last=True, rederive=None
+    )
+    assert result.returncode != 0
+    assert "conflicts with a concurrent publish" in result.stdout
+    published = QualificationReceipt.model_validate(
+        _published(origin, "qualification_receipt.json")
+    )
+    assert published.unreviewed_sha256 == receipt_b.unreviewed_sha256
+
+
+def _ledger_with_attempts(root: Path):
+    """A ledger pair with attempt A qualified (sequence 1) and B incomplete (2)."""
+
+    ledger = root / "ledger"
+    pair_dir = ledger / "uk" / PAIR.pair_id
+    _stage(pair_dir / "attempts" / "a", HARNESS, "1", "2026-10-15T09:00:00Z")
+    _complete_replay(pair_dir / "attempts" / "a", _request(HARNESS))
+    receipt_a = finalize_attempt(
+        pair_dir / "attempts" / "a",
+        ledger,
+        issued_by=ISSUED,
+        completed_at="2026-10-15T09:30:00Z",
+    )
+    _stage(pair_dir / "attempts" / "b", NEWER_HARNESS, "2", "2026-10-15T10:01:00Z")
+    receipt_b = finalize_attempt(
+        pair_dir / "attempts" / "b",
+        ledger,
+        issued_by=ISSUED,
+        completed_at="2026-10-15T10:02:00Z",
+    )
+    return ledger, pair_dir, receipt_a, receipt_b
+
+
+def _hybrid(receipt_a, receipt_b) -> dict:
+    """The round-6 merge: B's harness and identity with A's replay and gates."""
+
+    hybrid = receipt_a.canonical_payload()
+    hybrid["harness"] = receipt_b.harness.canonical_payload()
+    hybrid["issued_by"] = receipt_b.issued_by.canonical_payload()
+    QualificationReceipt.model_validate(hybrid)  # it is a valid-looking receipt
+    return hybrid
+
+
+def test_a_merged_receipt_is_refused_by_every_reader(tmp_path, monkeypatch):
+    ledger, pair_dir, receipt_a, receipt_b = _ledger_with_attempts(tmp_path)
+    assert published_receipt(pair_dir).unreviewed_sha256 == receipt_b.unreviewed_sha256
+    write_json(pair_dir / "qualification_receipt.json", _hybrid(receipt_a, receipt_b))
+
+    with pytest.raises(LedgerInconsistency, match="not the receipt of attempt b"):
+        published_receipt(pair_dir)
+    problems: list[str] = []
+    assert latest_receipts(ledger, problems=problems) == []
+    assert problems and PAIR.pair_id in problems[0]
+
+    import importlib.util
+
+    spec = importlib.util.spec_from_file_location("ledger_concurrency_cli", CLI)
+    cli = importlib.util.module_from_spec(spec)
+    spec.loader.exec_module(cli)
+
+    with pytest.raises(LedgerInconsistency):
+        cli.cmd_accept(
+            SimpleNamespace(
+                ledger=str(ledger),
+                pair_id=PAIR.pair_id,
+                reviewer="r",
+                receipt_sha256="0" * 64,
+                explanation="x",
+            )
+        )
+
+    assert (
+        rederive_publication(pair_dir).unreviewed_sha256 == receipt_b.unreviewed_sha256
+    )
+    assert published_receipt(pair_dir).unreviewed_sha256 == receipt_b.unreviewed_sha256
+
+
+def test_an_older_attempts_real_receipt_is_not_the_published_one(tmp_path):
+    """A stale but genuine receipt is refused too: the latest attempt decides."""
+
+    _, pair_dir, receipt_a, _ = _ledger_with_attempts(tmp_path)
+    write_json(pair_dir / "qualification_receipt.json", receipt_a.canonical_payload())
+    with pytest.raises(LedgerInconsistency):
+        published_receipt(pair_dir)
+
+
+def test_rederivation_keeps_a_review_acceptance_of_exactly_that_receipt(tmp_path):
+    from tests.qualification_fixtures import make_receipt
+
+    ledger = tmp_path / "ledger"
+    pair_dir = ledger / "uk" / PAIR.pair_id
+    _stage(pair_dir / "attempts" / "a", HARNESS, "1", "2026-10-15T09:00:00Z")
+    receipt = make_receipt(pair=PAIR, gate_results=gates(metrics_review="needs_review"))
+    assert receipt.verdict == "needs_review" and not receipt.promotable
+    write_json(
+        pair_dir / "attempts" / "a" / "qualification_receipt.json",
+        receipt.canonical_payload(),
+    )
+    accepted = accept_review(
+        receipt,
+        reviewer="reviewer",
+        accepted_receipt_sha256=receipt.unreviewed_sha256,
+        explanation="expected",
+        accepted_at="2026-10-15T11:00:00Z",
+    )
+    write_json(
+        pair_dir / "reviews" / f"{accepted.receipt_sha256}.json",
+        accepted.canonical_payload(),
+    )
+    # A published file a merge left unreadable is rewritten, keeping the review.
+    write_json(pair_dir / "qualification_receipt.json", {"not": "a receipt"})
+    rederived = rederive_publication(pair_dir)
+    assert rederived.review is not None and rederived.promotable
+    assert published_receipt(pair_dir) == rederived
+    assert read_json(pair_dir / "latest_attempt.json") == {
+        "attempt_key": "a",
+        "sequence": read_json(pair_dir / "attempts" / "a" / "staging.json")["sequence"],
+    }
+
+
+class _Response:
+    def __init__(self, text=None):
+        self.status_code = 404 if text is None else 200
+        self.text = text or ""
+
+    def raise_for_status(self):
+        return None
+
+
+def _remote(files: dict):
+    def get(url, timeout):
+        # The longest matching suffix wins: an attempt's receipt URL also ends
+        # with the pair's receipt path suffix.
+        matches = [suffix for suffix in files if url.endswith(suffix)]
+        if not matches:
+            return _Response(None)
+        value = files[max(matches, key=len)]
+        return _Response(None if value is None else json.dumps(value))
+
+    return get
+
+
+def test_a_fetched_receipt_must_be_its_named_attempts_receipt(tmp_path):
+    _, _, receipt_a, receipt_b = _ledger_with_attempts(tmp_path)
+    pointer = {"attempt_key": "b", "sequence": 2}
+    good = _remote(
+        {
+            f"{PAIR.pair_id}/qualification_receipt.json": receipt_b.canonical_payload(),
+            "/latest_attempt.json": pointer,
+            "/attempts/b/qualification_receipt.json": receipt_b.canonical_payload(),
+        }
+    )
+    assert (
+        fetch_ledger_receipt("uk", PAIR.pair_id, get=good).unreviewed_sha256
+        == receipt_b.unreviewed_sha256
+    )
+    merged = _remote(
+        {
+            f"{PAIR.pair_id}/qualification_receipt.json": _hybrid(receipt_a, receipt_b),
+            "/latest_attempt.json": pointer,
+            "/attempts/b/qualification_receipt.json": receipt_b.canonical_payload(),
+        }
+    )
+    with pytest.raises(LedgerInconsistency):
+        fetch_ledger_receipt("uk", PAIR.pair_id, get=merged)
+    unnamed = _remote(
+        {f"{PAIR.pair_id}/qualification_receipt.json": receipt_b.canonical_payload()}
+    )
+    with pytest.raises(LedgerInconsistency, match="names no attempt"):
+        fetch_ledger_receipt("uk", PAIR.pair_id, get=unnamed)
+    assert fetch_ledger_receipt("uk", PAIR.pair_id, get=_remote({})) is None
diff --git a/tests/test_qualified_pair_certification.py b/tests/test_qualified_pair_certification.py
index 3ce1d8cf..953dd192 100644
--- a/tests/test_qualified_pair_certification.py
+++ b/tests/test_qualified_pair_certification.py
@@ -535,10 +535,13 @@ def test_any_certified_field_differing_from_the_receipt_is_refused(field, value)
 
 def test_ledger_listing(tmp_path):
     qualified = make_receipt()
+    pair_dir = tmp_path / "uk" / qualified.pair_id
+    # A published receipt counts only as its latest attempt's own receipt.
     write_json(
-        tmp_path / "uk" / qualified.pair_id / "qualification_receipt.json",
+        pair_dir / "attempts" / "a" / "qualification_receipt.json",
         qualified.canonical_payload(),
     )
+    write_json(pair_dir / "qualification_receipt.json", qualified.canonical_payload())
     pending = (
         tmp_path / "uk" / ("b" * 64) / "attempts" / "abc" / "replay" / "request.json"
     )
diff --git a/tests/test_uk_qualification_pipeline.py b/tests/test_uk_qualification_pipeline.py
index c1fa015e..f210e103 100644
--- a/tests/test_uk_qualification_pipeline.py
+++ b/tests/test_uk_qualification_pipeline.py
@@ -653,7 +653,7 @@ def test_promote_readies_and_merges_only_the_qualified_commit(monkeypatch, tmp_p
     cli = importlib.util.module_from_spec(spec)
     spec.loader.exec_module(cli)
     calls = []
-    monkeypatch.setattr(cli, "latest_receipts", lambda root: [qualified])
+    monkeypatch.setattr(cli, "latest_receipts", lambda root, **_: [qualified])
     monkeypatch.setattr(
         cli, "subprocess", SimpleNamespace(run=lambda argv, **k: calls.append(argv))
     )
@@ -1077,6 +1077,21 @@ def test_newer_abandoned_stage_recovers_despite_an_older_replay_request(tmp_path
     assert (earlier / "replay" / "request.json").exists()
 
 
+def _publish_as_attempt(ledger, pair, receipt, key):
+    """Publish ``receipt`` as an earlier, unstaged attempt's own receipt.
+
+    A published receipt counts only as its latest attempt's receipt
+    (``published_receipt``), so the fixture records the attempt it came from.
+    """
+
+    pair_dir = ledger / "uk" / pair.pair_id
+    write_json(
+        pair_dir / "attempts" / key / "qualification_receipt.json",
+        receipt.canonical_payload(),
+    )
+    write_json(pair_dir / "qualification_receipt.json", receipt.canonical_payload())
+
+
 @pytest.mark.parametrize("verdict", ["qualified", "rejected"])
 @pytest.mark.parametrize("main_advanced", [False, True])
 @pytest.mark.parametrize("staged_base", ["a" * 40, "f" * 40])
@@ -1092,8 +1107,7 @@ def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
     results = gates(wheel_hashes="fail") if verdict == "rejected" else gates()
     terminal = make_receipt(pair=pair, gate_results=results)
     base = staged_base
-    published = tmp_path / "uk" / pair.pair_id / "qualification_receipt.json"
-    write_json(published, terminal.canonical_payload())
+    _publish_as_attempt(tmp_path, pair, terminal, "terminal")
     attempt = attempt_directory(tmp_path, "uk", pair.pair_id, base[:12] + "-2")
     payload = {
         "pair": pair.canonical_payload(),
@@ -1118,7 +1132,7 @@ def test_forced_stage_recovery_binds_the_terminal_receipt_it_supersedes(
     assert cli.main(["recoverable", "--ledger", str(tmp_path)]) == 0
     assert json.loads(capsys.readouterr().out) == payload
     changed = make_receipt(pair=pair, gate_results=gates(replay="fail"))
-    write_json(published, changed.canonical_payload())
+    _publish_as_attempt(tmp_path, pair, changed, "terminal-later")
     assert (
         candidate_action(pair, BUNDLE, tmp_path, base_commit=base, now=now)[0]
         == "duplicate"
@@ -1199,10 +1213,7 @@ def test_resolution_preserves_authorization_to_recover_forced_work(
         pair=pair,
         gate_results=gates(replay="fail") if verdict == "rejected" else gates(),
     )
-    write_json(
-        tmp_path / "uk" / pair.pair_id / "qualification_receipt.json",
-        terminal.canonical_payload(),
-    )
+    _publish_as_attempt(tmp_path, pair, terminal, "terminal")
     base = "a" * 40
     resolved = cli.ResolvedCandidate(
         pair,
diff --git a/tests/test_uk_qualification_workflow.py b/tests/test_uk_qualification_workflow.py
index ad81326b..a37b7ed1 100644
--- a/tests/test_uk_qualification_workflow.py
+++ b/tests/test_uk_qualification_workflow.py
@@ -160,7 +160,7 @@ def fake_run(argv, **kwargs):
         state_path.write_text(json.dumps(state))
         return SimpleNamespace(returncode=0)
 
-    monkeypatch.setattr(cli, "latest_receipts", lambda root: [qualified])
+    monkeypatch.setattr(cli, "latest_receipts", lambda root, **_: [qualified])
     monkeypatch.setattr(cli, "subprocess", SimpleNamespace(run=fake_run))
     monkeypatch.setattr(cli, "config", lambda: {"promotion": {"automatic": False}})
     if prepare_first:
@@ -293,7 +293,7 @@ def test_refresh_checks_reruns_only_failed_pr_runs_for_the_qualified_head(
         )
     branch = candidate_branch(receipt.pair)
     head = receipt.harness.git_commit if head_matches else "f" * 40
-    monkeypatch.setattr(cli, "latest_receipts", lambda root: [receipt])
+    monkeypatch.setattr(cli, "latest_receipts", lambda root, **_: [receipt])
     monkeypatch.setattr(cli, "_open_candidate_branches", lambda: {branch: head})
     runs = [
         {

From 2d0515031c61fdda0f471f6972010d085d7306ec Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Thu, 15 Oct 2026 15:02:10 -0400
Subject: [PATCH 33/45] Run every qualification step in the environment its job
 installed

The repository's .python-version asks for 3.14, while each qualification
job syncs a 3.13 environment with the uk and dev extras. A syncing
`uv run` would replace that environment with base dependencies, so the
snapshot, bundle, gate and replay steps could lose pytest and the
country model. Set UV_PYTHON to 3.13 and run each step with
`uv run --no-sync` after the explicit sync. The ledger re-derivation
hook now runs the interpreter each job provisioned: the system Python
where the job installs with `uv pip install --system`, and the synced
environment's interpreter in prepare and qualify.

Add the round-7 review's missing tests: a large move in the wrong
direction is never a response for an up or a down reform, honest or
with a lying tool verdict; and rederivation drops a review that accepts
another receipt or is not a valid acceptance. Each kills its mutant.

Co-Authored-By: Claude Opus 5.5 
---
 .github/workflows/certify-uk-release.yaml     | 33 ++++++++---
 .../test_qualification_ledger_concurrency.py  | 56 +++++++++++++++++++
 tests/test_uk_candidate_gates.py              | 21 +++++++
 tests/test_uk_qualification_workflow.py       | 45 +++++++++++++++
 4 files changed, 146 insertions(+), 9 deletions(-)

diff --git a/.github/workflows/certify-uk-release.yaml b/.github/workflows/certify-uk-release.yaml
index 6d2c6277..d9bf360b 100644
--- a/.github/workflows/certify-uk-release.yaml
+++ b/.github/workflows/certify-uk-release.yaml
@@ -51,12 +51,19 @@ env:
   LEDGER_BRANCH: uk-qualification-ledger
   UV_VERSION: "0.12.14"
   PYTHON_VERSION: "3.13"
+  # Keep equal to PYTHON_VERSION. The repository's .python-version asks for a
+  # newer Python, and every uv command here must use the 3.13 environment the
+  # job installed. For the same reason each `uv run` passes --no-sync: the
+  # environment is synchronized explicitly (with the uk and dev extras), and
+  # a step must run exactly that environment.
+  UV_PYTHON: "3.13"
   # Run by .github/qualification-ledger.sh, inside the ledger worktree, when a
   # concurrent publish touched a pair's published files: recompute them from
-  # the attempts rather than let git merge two receipts.
+  # the attempts rather than let git merge two receipts. This default uses
+  # the system Python that `uv pip install --system` provisions; jobs that
+  # `uv sync` override it with the synchronized environment's interpreter.
   LEDGER_REDERIVE: >-
-    uv run --project ${{ github.workspace }} python
-    ${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger
+    python ${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger
 
 jobs:
   resolve:
@@ -129,6 +136,10 @@ jobs:
     outputs:
       candidate_commit: ${{ steps.stage.outputs.candidate_commit }}
       duplicate: ${{ steps.duplicate.outputs.duplicate }}
+    env:
+      LEDGER_REDERIVE: >-
+        ${{ github.workspace }}/.venv/bin/python
+        ${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger
     steps:
       - name: Generate GitHub App token
         id: app-token
@@ -179,7 +190,7 @@ jobs:
           BRANCH: ${{ needs.resolve.outputs.branch }}
         run: |
           git switch -C "$BRANCH"
-          uv run python scripts/check_uk_candidate.py prepare \
+          uv run --no-sync python scripts/check_uk_candidate.py prepare \
             --candidate "$RUNNER_TEMP/candidate/candidate.json" \
             --out "$RUNNER_TEMP/prepared.json" --skip-snapshots
       - name: Install the candidate environment from the regenerated lock
@@ -190,12 +201,12 @@ jobs:
         env:
           HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
           PE_UPDATE_SNAPSHOTS: "1"
-        run: uv run pytest tests/test_household_calculator_snapshot.py -q
+        run: uv run --no-sync pytest tests/test_household_calculator_snapshot.py -q
       - name: Check the regenerated bundle
         if: steps.duplicate.outputs.duplicate == 'false'
         env:
           HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
-        run: uv run python scripts/bundle.py check --include-tros --strict-tros
+        run: uv run --no-sync python scripts/bundle.py check --include-tros --strict-tros
       - name: Commit and push the candidate commit
         if: steps.duplicate.outputs.duplicate == 'false'
         env:
@@ -220,7 +231,7 @@ jobs:
         if: steps.duplicate.outputs.duplicate == 'false'
         run: |
           .github/qualification-ledger.sh checkout ledger
-          uv run python scripts/check_uk_candidate.py stage \
+          uv run --no-sync python scripts/check_uk_candidate.py stage \
             --candidate "$RUNNER_TEMP/candidate/candidate.json" --ledger ledger
           .github/qualification-ledger.sh publish ledger \
             "Stage UK candidate ${{ needs.resolve.outputs.pair_id }} attempt ${{ needs.resolve.outputs.attempt_key }}"
@@ -251,6 +262,10 @@ jobs:
     concurrency:
       group: uk-candidate-${{ needs.resolve.outputs.pair_id }}
       cancel-in-progress: false
+    env:
+      LEDGER_REDERIVE: >-
+        ${{ github.workspace }}/.venv/bin/python
+        ${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger
     steps:
       - uses: actions/checkout@v6
         with:
@@ -270,7 +285,7 @@ jobs:
         env:
           HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
           ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }}
-        run: uv run python scripts/check_uk_candidate.py gates --attempt "$ATTEMPT" --work-dir "$RUNNER_TEMP/qualification"
+        run: uv run --no-sync python scripts/check_uk_candidate.py gates --attempt "$ATTEMPT" --work-dir "$RUNNER_TEMP/qualification"
       - name: Generate a GitHub App token for the scorecard
         id: scorecard-token
         continue-on-error: true
@@ -286,7 +301,7 @@ jobs:
         env:
           GH_TOKEN: ${{ steps.scorecard-token.outputs.token }}
           ATTEMPT: ledger/uk/${{ needs.resolve.outputs.pair_id }}/attempts/${{ needs.resolve.outputs.attempt_key }}
-        run: uv run python scripts/check_uk_candidate.py request-replay --attempt "$ATTEMPT" --dispatch
+        run: uv run --no-sync python scripts/check_uk_candidate.py request-replay --attempt "$ATTEMPT" --dispatch
       - name: Publish the gate evidence
         if: always()
         run: |
diff --git a/tests/test_qualification_ledger_concurrency.py b/tests/test_qualification_ledger_concurrency.py
index efb1f143..3ca61a03 100644
--- a/tests/test_qualification_ledger_concurrency.py
+++ b/tests/test_qualification_ledger_concurrency.py
@@ -34,6 +34,7 @@
     QualificationReceipt,
     ReplayReceipt,
     ReplayStatus,
+    ReviewAcceptance,
     evaluate_replay_receipt,
 )
 from policyengine.provenance.qualification_ledger import (
@@ -406,6 +407,61 @@ def test_rederivation_keeps_a_review_acceptance_of_exactly_that_receipt(tmp_path
     }
 
 
+@pytest.mark.parametrize("flaw", ["of another receipt", "not a valid acceptance"])
+def test_rederivation_drops_a_review_that_does_not_accept_that_receipt(tmp_path, flaw):
+    """Offered as the published file and as a stored review, an acceptance is
+    kept only if it promotes exactly the latest attempt's receipt."""
+
+    from tests.qualification_fixtures import make_receipt
+
+    pair_dir = tmp_path / "ledger" / "uk" / PAIR.pair_id
+    _stage(pair_dir / "attempts" / "a", HARNESS, "1", "2026-10-15T09:00:00Z")
+    receipt = make_receipt(pair=PAIR, gate_results=gates(metrics_review="needs_review"))
+    write_json(
+        pair_dir / "attempts" / "a" / "qualification_receipt.json",
+        receipt.canonical_payload(),
+    )
+    if flaw == "of another receipt":
+        other = make_receipt(
+            pair=PAIR,
+            gate_results=gates(metrics_review="needs_review"),
+            completed_at="2026-10-15T10:00:00Z",
+        )
+        assert other.unreviewed_sha256 != receipt.unreviewed_sha256
+        offered = accept_review(
+            other,
+            reviewer="reviewer",
+            accepted_receipt_sha256=other.unreviewed_sha256,
+            explanation="expected",
+            accepted_at="2026-10-15T11:00:00Z",
+        )
+        assert offered.promotable
+    else:
+        offered = QualificationReceipt.model_validate(
+            {
+                **receipt.canonical_payload(),
+                "review": ReviewAcceptance(
+                    reviewer="reviewer",
+                    accepted_at="2026-10-15T11:00:00Z",
+                    accepted_receipt_sha256="0" * 64,
+                    explanation="expected",
+                ).canonical_payload(),
+            }
+        )
+        assert offered.unreviewed_sha256 == receipt.unreviewed_sha256
+        assert offered.review is not None and not offered.promotable
+    write_json(
+        pair_dir / "reviews" / f"{offered.receipt_sha256}.json",
+        offered.canonical_payload(),
+    )
+    write_json(pair_dir / "qualification_receipt.json", offered.canonical_payload())
+
+    rederived = rederive_publication(pair_dir)
+    assert rederived.review is None and not rederived.promotable
+    assert rederived.unreviewed_sha256 == receipt.unreviewed_sha256
+    assert published_receipt(pair_dir) == rederived
+
+
 class _Response:
     def __init__(self, text=None):
         self.status_code = 404 if text is None else 200
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 6ddedd3b..540a0902 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -2275,6 +2275,27 @@ def test_the_tools_verdict_is_checked_against_its_own_numbers():
     assert _responsiveness(short).status in ("fail", "error")
 
 
+@pytest.mark.parametrize("direction", ["up", "down"])
+def test_a_large_move_in_the_wrong_direction_is_not_a_response(direction):
+    """A reform that moves its target the wrong way, by far more than the
+    minimum, has not responded, whatever the tool's verdict says. The
+    magnitude alone must never pass: the comparison is signed."""
+
+    reform = next(r for r in _standard_reforms() if r["direction"] == direction)
+    sign = 1.0 if direction == "up" else -1.0
+    wrong_way = {
+        (reform["id"], year): -sign * reform["minimum"] * 5.0 for year in RESPONSE_YEARS
+    }
+    honest = _responsiveness(_responsive_report(overrides=wrong_way))
+    assert honest.status == "fail"
+    assert f"({reform['id']}) did not respond" in honest.summary, honest.summary
+    lying_pass = _responsiveness(
+        _responsive_report(overrides=wrong_way, lie=reform["id"])
+    )
+    assert lying_pass.status == "error", lying_pass.summary
+    assert "do not meet the minimum" in lying_pass.summary
+
+
 def test_responsiveness_is_never_skipped_or_guessed():
     from policyengine.provenance.qualification import (
         REQUIRED_GATES,
diff --git a/tests/test_uk_qualification_workflow.py b/tests/test_uk_qualification_workflow.py
index a37b7ed1..6b4fb06c 100644
--- a/tests/test_uk_qualification_workflow.py
+++ b/tests/test_uk_qualification_workflow.py
@@ -50,6 +50,51 @@ def test_resolution_can_authenticate_the_staged_attempt_owner_lookup():
     assert step["env"]["GH_TOKEN"] == "${{ github.token }}"
 
 
+def test_every_uv_step_runs_the_environment_its_job_installed():
+    """The repository's .python-version asks for a newer Python than the 3.13
+    environment each job installs. A syncing `uv run` would replace that
+    environment, extras and all, so every step and the ledger re-derivation
+    must run the interpreter the job provisioned."""
+    workflow = _workflow()
+    assert (REPO_ROOT / ".python-version").read_text().strip() != (
+        workflow["env"]["PYTHON_VERSION"]
+    )
+    assert workflow["env"]["UV_PYTHON"] == workflow["env"]["PYTHON_VERSION"]
+    command = "${{ github.workspace }}/scripts/check_uk_candidate.py rederive-ledger"
+    publishing_jobs = []
+    for name, job in workflow["jobs"].items():
+        runs = [step.get("run", "") for step in job["steps"]]
+        synced = any(
+            "uv sync --frozen --extra uk --extra dev --python "
+            "${{ env.PYTHON_VERSION }}" in run
+            for run in runs
+        )
+        system = any("uv pip install --system" in run for run in runs)
+        assert not (synced and system), name
+        for line in (line for run in runs for line in run.splitlines()):
+            if "uv run" in line:
+                assert synced, (name, line)
+                assert "uv run --no-sync " in line, (name, line)
+        if any(".github/qualification-ledger.sh publish" in run for run in runs):
+            publishing_jobs.append(name)
+            rederive = job.get("env", {}).get(
+                "LEDGER_REDERIVE", workflow["env"]["LEDGER_REDERIVE"]
+            )
+            if synced:
+                interpreter = "${{ github.workspace }}/.venv/bin/python"
+            else:
+                assert system, name
+                interpreter = "python"
+            assert rederive == f"{interpreter} {command}", name
+    assert sorted(publishing_jobs) == [
+        "accept",
+        "catch-up",
+        "prepare",
+        "qualify",
+        "replay",
+    ]
+
+
 @pytest.mark.parametrize("prepare_first", [False, True])
 def test_head_replacement_and_readiness_share_one_serialization(
     monkeypatch, tmp_path, prepare_first

From 61155b5d1bc49620a8529c5ba8942c0fcec66f82 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Thu, 15 Oct 2026 16:30:03 -0400
Subject: [PATCH 34/45] Declare a historical report's checks as its own runner
 did

Main reworded the oracle of extended_freeze's 2034 personal allowance
check (and changed two CGT oracles with the realisation response). The
W1 full-run fixture comes from the 2.126.12-era runner, and two checks
share that 2034 label, told apart by oracle, so the test's declared
coverage, built from today's runner, no longer matched the report and
the gate found no unique identity. In production a report and its
declarations come from one installed runner. The test helper now
declares such a label as the report's runner did: one reworded
declaration takes the one recorded oracle no current declaration
matches.

Also pin round 8's Low: preparation syncs the candidate lock after
regenerating it and before snapshots, the bundle check and staging.
Deleting or moving that sync fails the new test.

Co-Authored-By: Claude Opus 5.5 
---
 tests/test_uk_candidate_gates.py        | 21 +++++++++++++++++++++
 tests/test_uk_qualification_workflow.py | 23 +++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 540a0902..5c2efa26 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -559,6 +559,27 @@ def _declared_coverage(source):
     by_case = {}
     for row in source.get("cases") or []:
         by_case.setdefault(row.get("case_id"), []).append(row)
+    # A historical report came from a runner whose oracle wording may differ
+    # from today's. Checks sharing a label are told apart by oracle, so
+    # declare them as that runner did: one reworded declaration takes the one
+    # recorded oracle no current declaration matches.
+    for (case_id, *label), checks in declared_checks.items():
+        check_label = ":".join(str(part) for part in label)
+        recorded = {
+            row.get("oracle")
+            for row in by_case.get(case_id, ())
+            if row.get("check") == check_label and row.get("oracle") is not None
+        }
+        current = {getattr(check, "oracle", None) for check in checks}
+        reworded = [check for check in checks if check.oracle not in recorded]
+        unmatched = recorded - current
+        if len(checks) > 1 and len(reworded) == 1 and len(unmatched) == 1:
+            declared_checks[(case_id, *label)] = [
+                SimpleNamespace(**{**vars(check), "oracle": next(iter(unmatched))})
+                if check is reworded[0]
+                else check
+                for check in checks
+            ]
     return {
         "ROUTES": tuple(source.get("routes") or ()),
         "CASES": tuple(
diff --git a/tests/test_uk_qualification_workflow.py b/tests/test_uk_qualification_workflow.py
index 6b4fb06c..88b57b4c 100644
--- a/tests/test_uk_qualification_workflow.py
+++ b/tests/test_uk_qualification_workflow.py
@@ -95,6 +95,29 @@ def test_every_uv_step_runs_the_environment_its_job_installed():
     ]
 
 
+def test_preparation_syncs_the_candidate_lock_before_using_it():
+    """Snapshots, the bundle check and staging must run in the candidate's
+    environment: synced from the lock preparation regenerates, after it is
+    regenerated, with the 3.13 interpreter and both extras."""
+
+    steps = _workflow()["jobs"]["prepare"]["steps"]
+    runs = [step.get("run", "") for step in steps]
+    sync = "uv sync --frozen --extra uk --extra dev --python ${{ env.PYTHON_VERSION }}"
+
+    def position(text):
+        return next(index for index, run in enumerate(runs) if text in run)
+
+    syncs = [index for index, run in enumerate(runs) if sync in run]
+    regenerate = position("check_uk_candidate.py prepare")
+    assert len(syncs) == 2 and syncs[0] < regenerate < syncs[1]
+    for later in (
+        "tests/test_household_calculator_snapshot.py",
+        "scripts/bundle.py check",
+        "check_uk_candidate.py stage",
+    ):
+        assert syncs[1] < position(later), later
+
+
 @pytest.mark.parametrize("prepare_first", [False, True])
 def test_head_replacement_and_readiness_share_one_serialization(
     monkeypatch, tmp_path, prepare_first

From a416230a76869bb664ed0a5d23d3aa65b6ae7a4d Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 00:27:39 -0400
Subject: [PATCH 35/45] Recognise contract 1.1.0's run-level row; gate a real
 1.1.0 full run

Round 9 of the review found a High CI could not see: the merge with main
brought contract 1.1.0, whose run-level row names the shared parameter
check "every parameter's dated values and metadata, and every node's
metadata and band order, in ...". The gate required the 1.0.0 wording
("... metadata in "), so every real run would have gated as an error and
every UK candidate been rejected. The gate now fixes only the stem both
contracts share (RUN_LEVEL_CHECK_PREFIX), and a test builds the row from
the installed runner itself; it fails on the old prefix.

CI stayed green because the 1.0.0 fixture no longer matched the runner's
contract version, so the 52 tests that gate a report through the real
runner's declarations skipped. tests/fixtures/uk_contract now holds a
real full run of contract 1.1.0 (the runner at this head, the certified
policyengine-uk 2.130.1 and core 3.33.0, uk-data 1.58.1's certified
dataset, seed 0, 20 examples): 792 pass, 25 pending a methodology call,
101 unsupported, both properties and all 19 population rows passing.
Those tests run again, and a fixture whose contract version the runner
has moved past now fails rather than skips. The 1.0.0 fixture and the
test helper's oracle pairing that bridged it are gone; the freeze test
selects the mandatory 2034 check by structure, not by its wording.

Twelve-file suite on the certified pair: 1502 passed, 3 skipped (was
1442 passed, 61 skipped).

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py   |     8 +-
 tests/fixtures/uk_contract/README.md          |     2 +-
 .../full_released_uk_2.126.12.json            |  8005 ---------
 .../uk_contract/full_released_uk_2.130.1.json | 14922 ++++++++++++++++
 tests/test_uk_candidate_gates.py              |   119 +-
 5 files changed, 14995 insertions(+), 8061 deletions(-)
 delete mode 100644 tests/fixtures/uk_contract/full_released_uk_2.126.12.json
 create mode 100644 tests/fixtures/uk_contract/full_released_uk_2.130.1.json

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 255b9a00..046ee1be 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -849,6 +849,10 @@ def _reported_assertions(
     ("population", "check_id", "population check"),
 )
 _CONTRACT_STATUSES = ("pass", "fail", "error", "unsupported", "pending")
+#: How the runner's run-level row names the shared parameter check. Contract
+#: 1.0.0 continued "in ..."; 1.1.0 added node metadata and band order before
+#: it, so only this stem is fixed.
+RUN_LEVEL_CHECK_PREFIX = "every parameter's dated values and metadata"
 
 
 def reform_contract(
@@ -1135,9 +1139,7 @@ def reform_contract(
                 )
             elif rows[0].get("status") not in ("pass", "fail", "error"):
                 malformed.append(f"run-level check {case}@{route} did not run")
-            elif not (rows[0].get("check") or "").startswith(
-                "every parameter's dated values and metadata in "
-            ):
+            elif not (rows[0].get("check") or "").startswith(RUN_LEVEL_CHECK_PREFIX):
                 malformed.append(
                     f"run-level check {case}@{route} does not identify the shared parameter check"
                 )
diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index 60dcc40c..3948b597 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -6,7 +6,7 @@ run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate
 
 - `pinned_uk_2.125.1_defects.json`: every case on policyengine-uk 2.125.1, the pinned model at the time, with `max_examples=2` and no dataset. The 66 failures and 35 errors are the dated-reform defects the contract was written to catch.
 - `full_allpass_uk_2.126.8.json`: the full run the gate expects. Every route and case, seed 0, `max_examples=20`, and population checks on the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`). The model was policyengine-uk 2.126.8 from the policyengine-uk#2305 branch with core 3.33.0, a development combination rather than a certified pair, so treat its `versions` as fixture metadata. Result: 267 pass, 6 pending decision d1344, 67 unsupported with reasons, both properties passing, 13 of 13 population checks; 20.6 minutes, peak RSS 2.7 GB.
-- `full_released_uk_2.126.12.json`: the full run on released policyengine-uk 2.126.12 with core 3.33.0 (12 October 2026, runner at main after #577, contract 1.0.0): every route and case, seed 0, `max_examples=20`, population checks on the certified `enhanced_frs_2024_25`. Result: 673 pass, 6 pending decision d1344, 79 unsupported with reasons, both properties passing, 19 of 19 population rows. A test gates it against the coverage the merged runner module declares.
+- `full_released_uk_2.130.1.json`: the full run of contract 1.1.0 (16 October 2026), the runner at policyengine.py#574's head merged with main 8a303636, on the certified pair policyengine-uk 2.130.1 with core 3.33.0: every route and case, seed 0, `max_examples=20`, population checks on the certified `enhanced_frs_2024_25` (uk-data 1.58.1, SHA-256 `056e80fd…`). Result: 792 pass, 25 pending a methodology call (d1344 and policyengine-uk#2396), 101 unsupported with reasons, both properties passing, 19 of 19 population rows; 29.6 minutes, peak RSS 3.5 GB. Its `versions` record policyengine 6.4.0, the stale metadata of the editable install that ran it; treat them as fixture metadata. The gate tests read it through the coverage the current runner module declares, and fail rather than skip when the runner's contract version moves past it. It replaces the 1.0.0 run on policyengine-uk 2.126.12.
 - `population_pass_max_examples_0.json`: population checks only, on the same dataset. It has no cases, and with `max_examples=0` its sampled properties did not run, so the gate treats it as an incomplete run.
 
 The only edits: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
diff --git a/tests/fixtures/uk_contract/full_released_uk_2.126.12.json b/tests/fixtures/uk_contract/full_released_uk_2.126.12.json
deleted file mode 100644
index 06e3f812..00000000
--- a/tests/fixtures/uk_contract/full_released_uk_2.126.12.json
+++ /dev/null
@@ -1,8005 +0,0 @@
-{
- "cases": [
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "unreformed_after_reform:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 51330.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "expected": 51330.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 987.12,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "expected": 987.12,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39300.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "expected": 39300.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52390.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "expected": 52390.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 251.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "expected": 251.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1007.5,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "expected": 1007.5,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 40100.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "expected": 40100.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 53460.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "expected": 53460.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 256.92,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "expected": 256.92,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1028.08,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "expected": 1028.08,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "expected": 13630.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "expected": 41000.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 51330.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "expected": 51330.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 987.12,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "expected": 987.12,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 39300.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "expected": 39300.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 52390.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "expected": 52390.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 251.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "expected": 251.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1007.5,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "expected": 1007.5,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 40100.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "expected": 40100.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 53460.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "expected": 53460.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 256.92,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "expected": 256.92,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1028.08,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "expected": 1028.08,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "expected": 13630.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "expected": 41000.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 51330.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "expected": 51330.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 987.12,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "expected": 987.12,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39300.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "expected": 39300.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13090.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "expected": 13090.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52390.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "expected": 52390.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 251.73,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "expected": 251.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1007.5,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "expected": 1007.5,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 40100.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "expected": 40100.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13360.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "expected": 13360.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 53460.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "expected": 53460.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 256.92,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "expected": 256.92,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1028.08,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "expected": 1028.08,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "expected": 13630.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "expected": 41000.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "unreformed_after_reform:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "unreformed_after_reform:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_benefit_uprating",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "unreformed_after_reform:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "variable:universal_credit:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "variable:universal_credit:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "variable:universal_credit:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "baseline_isolation:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "variable:universal_credit:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "variable:universal_credit:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "change:universal_credit:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2026",
-   "expected": 5098.7998046875,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": "unreformed_after_reform:universal_credit:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "uc_award_follows_the_standard_allowance",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 14560.0,
-   "case_id": "new_state_pension_rate",
-   "check": "variable:new_state_pension:2027",
-   "decision_id": null,
-   "expected": 14560.0,
-   "holds": null,
-   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "new_state_pension_rate",
-   "check": "change:new_state_pension:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 14560.0,
-   "case_id": "new_state_pension_rate",
-   "check": "variable:new_state_pension:2027",
-   "decision_id": null,
-   "expected": 14560.0,
-   "holds": null,
-   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "new_state_pension_rate",
-   "check": "change:new_state_pension:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 14560.0,
-   "case_id": "new_state_pension_rate",
-   "check": "variable:new_state_pension:2027",
-   "decision_id": null,
-   "expected": 14560.0,
-   "holds": null,
-   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "new_state_pension_rate",
-   "check": "change:new_state_pension:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "baseline_isolation:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 14560.0,
-   "case_id": "new_state_pension_rate",
-   "check": "variable:new_state_pension:2027",
-   "decision_id": null,
-   "expected": 14560.0,
-   "holds": null,
-   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
-   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "new_state_pension_rate",
-   "check": "change:new_state_pension:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 14560.0,
-   "case_id": "new_state_pension_rate",
-   "check": "variable:new_state_pension:2027",
-   "decision_id": null,
-   "expected": 14560.0,
-   "holds": null,
-   "oracle": "the full weekly rate x 52: \u00a3280 x 52",
-   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "new_state_pension_rate",
-   "check": "change:new_state_pension:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 13036.9736328125,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2027",
-   "expected": 13036.9736328125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 12547.599609375,
-   "case_id": "new_state_pension_rate",
-   "check": "unreformed_after_reform:new_state_pension:2026",
-   "expected": 12547.599609375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "new_state_pension_rate",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 60.8197021484375,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2027",
-   "decision_id": null,
-   "expected": 60.81967213114759,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 140.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2028",
-   "decision_id": null,
-   "expected": 139.99999999999994,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
-   "expected": 0.18,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 60.8197021484375,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2027",
-   "decision_id": null,
-   "expected": 60.81967213114759,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 140.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2028",
-   "decision_id": null,
-   "expected": 139.99999999999994,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
-   "expected": 0.18,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 60.8197021484375,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2027",
-   "decision_id": null,
-   "expected": 60.81967213114759,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 140.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2028",
-   "decision_id": null,
-   "expected": 139.99999999999994,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "baseline_isolation:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
-   "expected": 0.18,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
-   "expected": 0.18000000000000002,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 60.8197021484375,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2027",
-   "decision_id": null,
-   "expected": 60.81967213114759,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 140.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2028",
-   "decision_id": null,
-   "expected": 139.99999999999994,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 60.8197021484375,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2027",
-   "decision_id": null,
-   "expected": 60.81967213114759,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 140.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "change:capital_gains_tax:2028",
-   "decision_id": null,
-   "expected": 139.99999999999994,
-   "holds": null,
-   "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2026",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2027",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "mid_year_blended_rate",
-   "check": "unreformed_after_reform:capital_gains_tax:2028",
-   "expected": 1260.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12830.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "expected": 12830.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 38500.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "expected": 38500.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 246.73,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "expected": 246.73,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "unreformed_after_reform:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "unreformed_after_reform:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "unreformed_after_reform:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "unreformed_after_reform:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "unreformed_after_reform:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "unreformed_after_reform:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "structural_switch",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 526.3154296875,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "change:vat:2026",
-   "decision_id": null,
-   "expected": 526.3157894736839,
-   "holds": null,
-   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 526.3154296875,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "change:vat:2026",
-   "decision_id": null,
-   "expected": 526.3157894736839,
-   "holds": null,
-   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 526.3154296875,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "change:vat:2026",
-   "decision_id": null,
-   "expected": 526.3157894736839,
-   "holds": null,
-   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 526.3154296875,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "change:vat:2026",
-   "decision_id": null,
-   "expected": 526.3157894736839,
-   "holds": null,
-   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
-   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "reason": "the policy route's output dataset holds the reformed run only",
-   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 526.3154296875,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "change:vat:2026",
-   "decision_id": null,
-   "expected": 526.3157894736839,
-   "holds": null,
-   "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
-   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "unreformed_after_reform:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "baseline_vat_is_current_law",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "modifier_then_parameter_changes",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "modifier_then_parameter_changes",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0875,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.0875,
-   "holds": null,
-   "oracle": "set by the modifier",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.1075,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "expected": 0.1075,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "parameter_changes_then_modifier",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": -190.0,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": -190.00000000000003,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": -15.7001953125,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": -15.700000000000358,
-   "holds": null,
-   "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2026",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 4507.25,
-   "case_id": "parameter_changes_then_modifier",
-   "check": "unreformed_after_reform:income_tax:2027",
-   "expected": 4507.25,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "unknown_path",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "fiscal year 2027",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "that year only",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before 1 January 2027",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "from 1 January 2027",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "onwards",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "one day is not 30 April",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "one day only",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "expected": 0.2,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "unreformed_after_reform:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "unreformed_after_reform:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "an unreformed simulation built after the reform equals one built before it",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": "unchanged",
-   "case_id": "module_parameters_unchanged",
-   "check": "every parameter's dated values and metadata in processed, projected, statutory, system",
-   "expected": "policyengine-uk's shared parameters as they were before the run",
-   "oracle": "the shared parameter state's values, read before any reform ran",
-   "reform_digest": null,
-   "route": "all",
-   "status": "pass"
-  }
- ],
- "contract_id": "policyengine-uk/budget-reform-contract",
- "contract_version": "1.0.0",
- "dataset": {
-  "path": "",
-  "sha256": "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
- },
- "holds": true,
- "max_examples": 20,
- "population": [
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "unreformed",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_query_order",
-   "detail": null,
-   "route": "unreformed",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_routes_agree",
-   "route": "country.reform_dict = country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_routes_agree",
-   "route": "country.reform_dict = country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0,
-    "2027_total_change": 205718.88776016235
-   },
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0,
-    "2027_total_change": 205718.88776016235
-   },
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0,
-    "2027_total_change": 205718.88776016235
-   },
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_uc_standard_allowance_plus_10",
-   "detail": {
-    "awards_higher": 105,
-    "awards_lower": 0,
-    "standard_allowance_scaled_10_percent": true
-   },
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_uc_standard_allowance_plus_10",
-   "detail": {
-    "awards_higher": 105,
-    "awards_lower": 0,
-    "standard_allowance_scaled_10_percent": true
-   },
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_uc_standard_allowance_plus_10",
-   "detail": {
-    "awards_higher": 105,
-    "awards_lower": 0,
-    "standard_allowance_scaled_10_percent": true
-   },
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_state_pension_plus_10",
-   "detail": {
-    "basic_and_new_scaled_10_percent": true,
-    "pensions_higher": 507,
-    "pensions_lower": 0
-   },
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_state_pension_plus_10",
-   "detail": {
-    "basic_and_new_scaled_10_percent": true,
-    "pensions_higher": 507,
-    "pensions_lower": 0
-   },
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_state_pension_plus_10",
-   "detail": {
-    "basic_and_new_scaled_10_percent": true,
-    "pensions_higher": 507,
-    "pensions_lower": 0
-   },
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  }
- ],
- "prior_law_option": "projected",
- "properties": [
-  {
-   "engine": "hypothesis",
-   "examples_run": 20,
-   "property_id": "annual_values_match_the_oracle",
-   "status": "pass"
-  },
-  {
-   "engine": "hypothesis",
-   "examples_run": 20,
-   "property_id": "routes_agree_and_baselines_hold",
-   "status": "pass"
-  }
- ],
- "routes": [
-  "country.reform_dict",
-  "country.scenario_parameter_changes",
-  "country.reform_from_dict",
-  "wrapper.household",
-  "wrapper.policy",
-  "api.sim_api"
- ],
- "seed": 0,
- "summary": {
-  "error": 0,
-  "fail": 0,
-  "pass": 673,
-  "pending": 6,
-  "unsupported": 79
- },
- "versions": {
-  "policyengine": "6.2.7",
-  "policyengine-core": "3.33.0",
-  "policyengine-uk": "2.126.12"
- }
-}
diff --git a/tests/fixtures/uk_contract/full_released_uk_2.130.1.json b/tests/fixtures/uk_contract/full_released_uk_2.130.1.json
new file mode 100644
index 00000000..b19bbd81
--- /dev/null
+++ b/tests/fixtures/uk_contract/full_released_uk_2.130.1.json
@@ -0,0 +1,14922 @@
+{
+  "cases": [
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "unchanged before 2027-28",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "held from 6 April 2027",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2026:3",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:4",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2028:5",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "9f0a954308ede698ebada30899f04339b96ed509cb4ebe07c3885c229a9645f4",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "unchanged before 2027-28",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "held from 6 April 2027",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2026:3",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:4",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2028:5",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "979484c0e230b3255e62c00e7bad677dcf6b7839f97ff732a647828c0f14f46e",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "unchanged before 2027-28",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "held from 6 April 2027",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2026:3",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:4",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2028:5",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2026:3",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:4",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2028:5",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "april_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2026:3",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:4",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2028:5",
+      "case_id": "april_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "april_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_rate_change",
+        "reform_sha256": "e9c1d3beb83179ffb9bb369d900a2f264eda9535f67431adcc31bf5f03ca86b1",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "april_rate_change",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "prior law after 5 April 2028",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:2",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2028:3",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "the change has ended",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "1435fd005a02984184442093db0558b51cf444c5a9e03bdbd4a2279e4b135105",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "prior law after 5 April 2028",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:2",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2028:3",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "the change has ended",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "ae43ea29444561c5c77d32ad9834b0075bd62c00d605154065a304dd0055e229",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "prior law after 5 April 2028",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:2",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2028:3",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "the change has ended",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "baseline_isolation:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:2",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2028:3",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "the change has ended",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "finite_rate_change",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 174.300048828125,
+      "assertion_id": "change:income_tax:2027:2",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": 174.29999999999967,
+      "holds": null,
+      "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:income_tax:2028:3",
+      "case_id": "finite_rate_change",
+      "check": "change:income_tax:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "the change has ended",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3486.0,
+      "case_id": "finite_rate_change",
+      "check": "unreformed_after_reform:income_tax:2028",
+      "expected": 3486.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "finite_rate_change",
+        "reform_sha256": "9413545a91d0019e0b4c06272d040c0948378d600c25eba395341396be96f98a",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "finite_rate_change",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031:2",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031:3",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:4",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031:5",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 52.0,
+      "assertion_id": "change:income_tax:2031:6",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2031",
+      "decision_id": null,
+      "expected": 52.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032:7",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032:8",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032:9",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032:10",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032:11",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032:12",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 104.0,
+      "assertion_id": "change:income_tax:2032:13",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2032",
+      "decision_id": null,
+      "expected": 104.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033:14",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033:15",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033:16",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033:17",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033:18",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033:19",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 158.0,
+      "assertion_id": "change:income_tax:2033:20",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2033",
+      "decision_id": null,
+      "expected": 158.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:21",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": null,
+      "expected": 13630.0,
+      "holds": null,
+      "oracle": "prior law's projected path resumes (PRIOR_LAW_OPTION)",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:22",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": "d1344",
+      "expected": 12830.0,
+      "holds": false,
+      "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 41000.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034:23",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "decision_id": "d1344",
+      "expected": 38500.0,
+      "holds": false,
+      "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 51330.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "expected": 51330.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 987.12,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "expected": 987.12,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 39300.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "expected": 39300.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 52390.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "expected": 52390.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 251.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "expected": 251.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1007.5,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "expected": 1007.5,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 40100.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "expected": 40100.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 53460.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "expected": 53460.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 256.92,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "expected": 256.92,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1028.08,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "expected": 1028.08,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "expected": 13630.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 41000.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "expected": 41000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "1b943da8e8bc75c3d0e6d96ab325eaca5480e5798ad4dbc239037eec6371061c",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031:2",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031:3",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:4",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031:5",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 52.0,
+      "assertion_id": "change:income_tax:2031:6",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2031",
+      "decision_id": null,
+      "expected": 52.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032:7",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032:8",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032:9",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032:10",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032:11",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032:12",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 104.0,
+      "assertion_id": "change:income_tax:2032:13",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2032",
+      "decision_id": null,
+      "expected": 104.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033:14",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033:15",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033:16",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033:17",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033:18",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033:19",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 158.0,
+      "assertion_id": "change:income_tax:2033:20",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2033",
+      "decision_id": null,
+      "expected": 158.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:21",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": null,
+      "expected": 13630.0,
+      "holds": null,
+      "oracle": "prior law's projected path resumes (PRIOR_LAW_OPTION)",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:22",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": "d1344",
+      "expected": 12830.0,
+      "holds": false,
+      "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 41000.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034:23",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "decision_id": "d1344",
+      "expected": 38500.0,
+      "holds": false,
+      "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 51330.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "expected": 51330.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 987.12,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "expected": 987.12,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 39300.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "expected": 39300.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 52390.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "expected": 52390.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 251.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "expected": 251.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1007.5,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "expected": 1007.5,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 40100.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "expected": 40100.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 53460.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "expected": 53460.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 256.92,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "expected": 256.92,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1028.08,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "expected": 1028.08,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "expected": 13630.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 41000.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "expected": 41000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "83e1d809ac3a20b0669fcf3bf857cd0640aadd1be0b7713ea248fd96a7d38326",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031:2",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031:3",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:4",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031:5",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 52.0,
+      "assertion_id": "change:income_tax:2031:6",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2031",
+      "decision_id": null,
+      "expected": 52.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032:7",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032:8",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032:9",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032:10",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032:11",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032:12",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 104.0,
+      "assertion_id": "change:income_tax:2032:13",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2032",
+      "decision_id": null,
+      "expected": 104.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033:14",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 37700.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033:15",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "decision_id": null,
+      "expected": 37700.0,
+      "holds": null,
+      "oracle": "frozen",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12570.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033:16",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "decision_id": null,
+      "expected": 12570.0,
+      "holds": null,
+      "oracle": "aligned with the allowance",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 50270.0,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033:17",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "decision_id": null,
+      "expected": 50270.0,
+      "holds": null,
+      "oracle": "allowance + basic rate limit",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 241.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033:18",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "decision_id": null,
+      "expected": 241.73,
+      "holds": null,
+      "oracle": "12,570 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 966.73,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033:19",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "decision_id": null,
+      "expected": 966.73,
+      "holds": null,
+      "oracle": "50,270 / 52, to the penny",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 158.0,
+      "assertion_id": "change:income_tax:2033:20",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2033",
+      "decision_id": null,
+      "expected": 158.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:21",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": null,
+      "expected": 13630.0,
+      "holds": null,
+      "oracle": "prior law's projected path resumes (PRIOR_LAW_OPTION)",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:22",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "decision_id": "d1344",
+      "expected": 12830.0,
+      "holds": false,
+      "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 41000.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034:23",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "decision_id": "d1344",
+      "expected": 38500.0,
+      "holds": false,
+      "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "baseline_isolation:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 51330.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "expected": 51330.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 987.12,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "expected": 987.12,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 39300.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "expected": 39300.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13090.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "expected": 13090.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 52390.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "expected": 52390.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 251.73,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "expected": 251.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1007.5,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "expected": 1007.5,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 40100.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "expected": 40100.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13360.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "expected": 13360.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 53460.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "expected": 53460.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 256.92,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "expected": 256.92,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1028.08,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "expected": 1028.08,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13630.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "expected": 13630.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 41000.0,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "expected": 41000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031:2",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031:3",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:4",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031:5",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 52.0,
+      "assertion_id": "change:income_tax:2031:6",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2031",
+      "decision_id": null,
+      "expected": 52.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032:7",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032:8",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032:9",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032:10",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032:11",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032:12",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 104.0,
+      "assertion_id": "change:income_tax:2032:13",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2032",
+      "decision_id": null,
+      "expected": 104.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033:14",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033:15",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033:16",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033:17",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033:18",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033:19",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 158.0,
+      "assertion_id": "change:income_tax:2033:20",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2033",
+      "decision_id": null,
+      "expected": 158.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:21",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:22",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034:23",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031:2",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031:3",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:4",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031:5",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 52.0,
+      "assertion_id": "change:income_tax:2031:6",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2031",
+      "decision_id": null,
+      "expected": 52.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032:7",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032:8",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032:9",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032:10",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032:11",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032:12",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 104.0,
+      "assertion_id": "change:income_tax:2032:13",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2032",
+      "decision_id": null,
+      "expected": 104.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033:14",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033:15",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033:16",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033:17",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033:18",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033:19",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 158.0,
+      "assertion_id": "change:income_tax:2033:20",
+      "case_id": "extended_freeze",
+      "check": "change:income_tax:2033",
+      "decision_id": null,
+      "expected": 158.0,
+      "holds": null,
+      "oracle": "basic rate x (current law's allowance - 12,570)",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:21",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034:22",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034:23",
+      "case_id": "extended_freeze",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 3424.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2031",
+      "expected": 3424.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3372.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2032",
+      "expected": 3372.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 3318.39990234375,
+      "case_id": "extended_freeze",
+      "check": "unreformed_after_reform:income_tax:2033",
+      "expected": 3318.39990234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "extended_freeze",
+        "reform_sha256": "8bcc44861af52ebd02b59342635d00e9900379ee1901ac755ea7443cb09d3d7c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "extended_freeze",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2029:2",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2029",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "held from April 2028",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2026:3",
+      "case_id": "april_benefit_uprating",
+      "check": "change:uc_standard_allowance:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "88407c594dab2d57ead4d2a0f358716dfef6f595741e7abbb206bc51bed87701",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2029:2",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2029",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "held from April 2028",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2026:3",
+      "case_id": "april_benefit_uprating",
+      "check": "change:uc_standard_allowance:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "40b2c4441a2078ee36efae8485cf7f09a44d30a419fe1a728ca638c0453e9d47",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2029:2",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2029",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "held from April 2028",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2026:3",
+      "case_id": "april_benefit_uprating",
+      "check": "change:uc_standard_allowance:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "baseline_isolation:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2029:2",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2029",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "held from April 2028",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2026:3",
+      "case_id": "april_benefit_uprating",
+      "check": "change:uc_standard_allowance:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2029:2",
+      "case_id": "april_benefit_uprating",
+      "check": "variable:uc_standard_allowance:2029",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "held from April 2028",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2026:3",
+      "case_id": "april_benefit_uprating",
+      "check": "change:uc_standard_allowance:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5426.7763671875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2029",
+      "expected": 5426.7763671875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "april_benefit_uprating",
+      "check": "unreformed_after_reform:uc_standard_allowance:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "april_benefit_uprating",
+        "reform_sha256": "58e9d16e27a4dc0684cf02ecd1faafe3130e0ef7580678b9828ba90050e8b5b4",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "april_benefit_uprating",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2028:1",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2030:2",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2030",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2028:1",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2030:2",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2030",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2028:1",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2030:2",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2030",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "baseline_isolation:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2028:1",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2030:2",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2030",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2028:1",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:uc_standard_allowance:2030:2",
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "change:uc_standard_allowance:2030",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5535.2998046875,
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": "unreformed_after_reform:uc_standard_allowance:2030",
+      "expected": 5535.2998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "bounded_change_on_uprated_benefit",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "bounded_change_on_uprated_benefit",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:universal_credit:2027:0",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "variable:universal_credit:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2026:1",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2028:2",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "db26dec4b5e242418423a73dd50b1e505234e3cabc766b7a69c6b090861fc222",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:universal_credit:2027:0",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "variable:universal_credit:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2026:1",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2028:2",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "51108be17b7300ba327842351ba352d0348dc28541775d7ebb8f6996b163b058",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:universal_credit:2027:0",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "variable:universal_credit:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2026:1",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2028:2",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "baseline_isolation:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:universal_credit:2027:0",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "variable:universal_credit:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2026:1",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2028:2",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:universal_credit:2027:0",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "variable:universal_credit:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "with no income or other elements, the award is the standard allowance: \u00a3500 x 12",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2026:1",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:universal_credit:2028:2",
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "change:universal_credit:2028",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "prior law's uprated path resumes",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5098.7998046875,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2026",
+      "expected": 5098.7998046875,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": "unreformed_after_reform:universal_credit:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_award_follows_the_standard_allowance",
+        "reform_sha256": "1fab70cb70b7ee142be73c2e6b4b6e9056e2c2562393a351b226ee865bcaaf32",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "uc_award_follows_the_standard_allowance",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 14560.0,
+      "assertion_id": "variable:new_state_pension:2027:0",
+      "case_id": "new_state_pension_rate",
+      "check": "variable:new_state_pension:2027",
+      "decision_id": null,
+      "expected": 14560.0,
+      "holds": null,
+      "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:new_state_pension:2026:1",
+      "case_id": "new_state_pension_rate",
+      "check": "change:new_state_pension:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "7c9f24257e0db73b283f97e34d0226bb7ef3deeb87e53cb9b6d8ae0813d8ffef",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0945e3ed8790352bb34d002b0f6c9dbabc55112d4f836a05c72e546a3c445026",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 14560.0,
+      "assertion_id": "variable:new_state_pension:2027:0",
+      "case_id": "new_state_pension_rate",
+      "check": "variable:new_state_pension:2027",
+      "decision_id": null,
+      "expected": 14560.0,
+      "holds": null,
+      "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:new_state_pension:2026:1",
+      "case_id": "new_state_pension_rate",
+      "check": "change:new_state_pension:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c3d7325ace7970b8e9ee72145bbd5355a951fb28634263fe8d45bf5b5bef852b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "0dcc940a6844540a4b247471f865123986aa0880e6db798bd4cdf9e1d39d7afa",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 14560.0,
+      "assertion_id": "variable:new_state_pension:2027:0",
+      "case_id": "new_state_pension_rate",
+      "check": "variable:new_state_pension:2027",
+      "decision_id": null,
+      "expected": 14560.0,
+      "holds": null,
+      "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:new_state_pension:2026:1",
+      "case_id": "new_state_pension_rate",
+      "check": "change:new_state_pension:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "baseline_isolation:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "2d1c4aca40ef23e4e38ee649a9a1326147605eb994e0a45c159dc41f9bb6916e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 14560.0,
+      "assertion_id": "variable:new_state_pension:2027:0",
+      "case_id": "new_state_pension_rate",
+      "check": "variable:new_state_pension:2027",
+      "decision_id": null,
+      "expected": 14560.0,
+      "holds": null,
+      "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+      "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:new_state_pension:2026:1",
+      "case_id": "new_state_pension_rate",
+      "check": "change:new_state_pension:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0b2bf84c45612ec5d6e3801f4f9e65f4c60f4790c0fec009a23e2740fb01a88a",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 14560.0,
+      "assertion_id": "variable:new_state_pension:2027:0",
+      "case_id": "new_state_pension_rate",
+      "check": "variable:new_state_pension:2027",
+      "decision_id": null,
+      "expected": 14560.0,
+      "holds": null,
+      "oracle": "the full weekly rate x 52: \u00a3280 x 52",
+      "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:new_state_pension:2026:1",
+      "case_id": "new_state_pension_rate",
+      "check": "change:new_state_pension:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 13036.9736328125,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2027",
+      "expected": 13036.9736328125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 12547.599609375,
+      "case_id": "new_state_pension_rate",
+      "check": "unreformed_after_reform:new_state_pension:2026",
+      "expected": 12547.599609375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52299dd48f65858b74ac05e1fb951f0b751dd0a6ed3430393643797f95ef5fff",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "new_state_pension_rate",
+        "reform_sha256": "1adb71bb9501e5eac518c2a5052887d74f26bd50c5d31f80a7e4a93d48ebdf63",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "new_state_pension_rate",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.18868852459016394,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.18868852459016502,
+      "holds": null,
+      "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2028:1",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2026:2",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+      "decision_id": null,
+      "expected": 0.18,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:3",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:4",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:5",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:6",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 60.8197021484375,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 60.81967213114759,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2028:8",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2028",
+      "decision_id": null,
+      "expected": 139.99999999999994,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd206e406d990aac403379d58a58e04950c54aff179efbe8895d52f08fd8902b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "2f6ae5060f9aee2dca401328ce7681920741c0202fb7a5b4c86823c6f7ca5ea3",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18868852459016394,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.18868852459016502,
+      "holds": null,
+      "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2028:1",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2026:2",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+      "decision_id": null,
+      "expected": 0.18,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:3",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:4",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:5",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:6",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 60.8197021484375,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 60.81967213114759,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2028:8",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2028",
+      "decision_id": null,
+      "expected": 139.99999999999994,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "0059b42d41bee7074a7f0a19cf2e9590ce1562cb6874e147557f6aaba3bc1a0b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "5d2bd0b5a49e1642b8c3eb392de195c894cd9b44946abda008c23fc1a022fa90",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18868852459016394,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.18868852459016502,
+      "holds": null,
+      "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2028:1",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2026:2",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+      "decision_id": null,
+      "expected": 0.18,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:3",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:4",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:5",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:6",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 60.8197021484375,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 60.81967213114759,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2028:8",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2028",
+      "decision_id": null,
+      "expected": 139.99999999999994,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "baseline_isolation:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2028",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18000000000000002,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2026",
+      "expected": 0.18000000000000002,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e648a4ec5d8f272d78a1128c21ed611c08a573f6c4a332d46f068bf72d164296",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2028:1",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2026:2",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:3",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:4",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:5",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:6",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 60.8197021484375,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 60.81967213114759,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2028:8",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2028",
+      "decision_id": null,
+      "expected": 139.99999999999994,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3b5170cc3cd245b56b3545d2b8c83bce7846ea472317ca194dff12ced488a05b",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2028:1",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2026:2",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:3",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:4",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:5",
+      "case_id": "mid_year_blended_rate",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:6",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 60.8197021484375,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 60.81967213114759,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; 159 of 2027-28's 366 days",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2028:8",
+      "case_id": "mid_year_blended_rate",
+      "check": "change:capital_gains_tax:2028",
+      "decision_id": null,
+      "expected": 139.99999999999994,
+      "holds": null,
+      "oracle": "(\u00a310,000 of gains - the annual exempt amount) x (20% - current rate) x the share of the tax year at 20%, with realisations held fixed; the gains sit wholly in the basic rate band, and the exempt amount and current rate are read from current law; all of 2028-29",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "mid_year_blended_rate",
+      "check": "unreformed_after_reform:capital_gains_tax:2028",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "10b81ccc8d17c82f2ba48d5b76f3a79a839d78d4fb357baeffe41c3074ca7475",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "mid_year_blended_rate",
+        "reform_sha256": "a7a024bbd0510652b8da6f8fbf64855b1f11f3debeb8cfbb0af0c3e5510d8db5",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "mid_year_blended_rate",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:1",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 1.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:2",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:3",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:4",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2026:5",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2026",
+      "decision_id": null,
+      "expected": 10000.0,
+      "holds": null,
+      "oracle": "no rate change before 2027-28, so no response",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 9756.09765625,
+      "assertion_id": "variable:capital_gains:2027:6",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": null,
+      "expected": 9756.09756097561,
+      "holds": null,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 91.2196044921875,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 91.21951219512198,
+      "holds": null,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9b906fb9819dd70ed26b3007c7219bd4de7fe8a13d34f1aab4c9bb8520e2af12",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "e8ad1a80f3c772e8125843e9caafda1a29bb70b536c992ff6c1cfc64ab411636",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:1",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 1.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:2",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:3",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:4",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2026:5",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2026",
+      "decision_id": null,
+      "expected": 10000.0,
+      "holds": null,
+      "oracle": "no rate change before 2027-28, so no response",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 9756.09765625,
+      "assertion_id": "variable:capital_gains:2027:6",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": null,
+      "expected": 9756.09756097561,
+      "holds": null,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 91.2196044921875,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 91.21951219512198,
+      "holds": null,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "c5a197e63745011018a30ab33fb6818e06ca5f0a910c0738dd17e6ddc3007fcf",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "0362c64a95b43a701e46cb6dfe0ee72dcc1d9bc6bb5dd5357e6a4be7782c52e0",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "in force all year",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:1",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": null,
+      "expected": 1.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:2",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:3",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "set by the case",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:4",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2026:5",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2026",
+      "decision_id": null,
+      "expected": 10000.0,
+      "holds": null,
+      "oracle": "no rate change before 2027-28, so no response",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 9756.09765625,
+      "assertion_id": "variable:capital_gains:2027:6",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": null,
+      "expected": 9756.09756097561,
+      "holds": null,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 91.2196044921875,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 91.21951219512198,
+      "holds": null,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.18,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.hmrc.cgt.basic_rate:2027",
+      "expected": 0.18,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f1418e77536fc627923bd4334ebc6c54d3325ce309ad10c411236338881b03dc",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:1",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:2",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:3",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:4",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2026:5",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2026",
+      "decision_id": null,
+      "expected": 10000.0,
+      "holds": null,
+      "oracle": "no rate change before 2027-28, so no response",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 9756.09765625,
+      "assertion_id": "variable:capital_gains:2027:6",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": null,
+      "expected": 9756.09756097561,
+      "holds": null,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 91.2196044921875,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 91.21951219512198,
+      "holds": null,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "a98f7df8e58f2b3387b99f3fb49d4e89b89d80fe96c5fe8c947346818a4dd929",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.cgt.basic_rate:2027:0",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:1",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:2",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:3",
+      "case_id": "cgt_retention_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "change:capital_gains_tax:2026:4",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2026",
+      "decision_id": null,
+      "expected": 0.0,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2026:5",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2026",
+      "decision_id": null,
+      "expected": 10000.0,
+      "holds": null,
+      "oracle": "no rate change before 2027-28, so no response",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 9756.09765625,
+      "assertion_id": "variable:capital_gains:2027:6",
+      "case_id": "cgt_retention_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": null,
+      "expected": 9756.09756097561,
+      "holds": null,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 91.2196044921875,
+      "assertion_id": "change:capital_gains_tax:2027:7",
+      "case_id": "cgt_retention_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": null,
+      "expected": 91.21951219512198,
+      "holds": null,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2026",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2026",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_retention_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd7e26a199e3488efbfdb64444be1cb27181109336dcd506dd61c7d960bba1de",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_retention_response",
+        "reform_sha256": "49e775a750c127c8dda5bed6e5651145d63d3330d50a836a460e64e2e81bb9d3",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "cgt_retention_response",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:0",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 1.0,
+      "holds": false,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:1",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:2",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2027:3",
+      "case_id": "cgt_default_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 9756.09756097561,
+      "holds": false,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law, at the default elasticity of 1",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2027:4",
+      "case_id": "cgt_default_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 91.21951219512198,
+      "holds": false,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law, at the default elasticity of 1",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b979620ae16eb9d24e950ef679de4d8a60c71049f84205fabdfbaad610e64c18",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "18e7b253186aea4b35258a26537cf8ee7fa6f8754a8eb762dd217b59b7b372b7",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:0",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 1.0,
+      "holds": false,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:1",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:2",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2027:3",
+      "case_id": "cgt_default_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 9756.09756097561,
+      "holds": false,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law, at the default elasticity of 1",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2027:4",
+      "case_id": "cgt_default_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 91.21951219512198,
+      "holds": false,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law, at the default elasticity of 1",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fd0f0568eb35b8455afcad278ed5e34a65d9520e6e79e16e9e5368ab535a0039",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "d9d5ec83a4ed5dd9a7efa2ead3ebc680e98472a1f5996b7845cbe5d9a586254b",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:0",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 1.0,
+      "holds": false,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:1",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 0.0,
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:2",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 0.0,
+      "holds": true,
+      "oracle": "policyengine-uk's default",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2027:3",
+      "case_id": "cgt_default_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 9756.09756097561,
+      "holds": false,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law, at the default elasticity of 1",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2027:4",
+      "case_id": "cgt_default_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 91.21951219512198,
+      "holds": false,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law, at the default elasticity of 1",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "baseline_isolation:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "52bd8c4df9f94da32c4f7f498f38c2aeef358a10348789e0fbe91a76f8d9834e",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:0",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:1",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:2",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "unsupported"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2027:3",
+      "case_id": "cgt_default_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 9756.09756097561,
+      "holds": false,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law, at the default elasticity of 1",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pending"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2027:4",
+      "case_id": "cgt_default_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 91.21951219512198,
+      "holds": false,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law, at the default elasticity of 1",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3ebd86525cf3d9fa26d8b326b94c85e358440ba7def9f8062ca337aef583ca68",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.elasticity:2027:0",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027:1",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.mtr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027:2",
+      "case_id": "cgt_default_response",
+      "check": "parameter:gov.simulation.capital_gains_responses.separate_badr_elasticity:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 10000.0,
+      "assertion_id": "variable:capital_gains:2027:3",
+      "case_id": "cgt_default_response",
+      "check": "variable:capital_gains:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 9756.09756097561,
+      "holds": false,
+      "oracle": "\u00a310,000 of gains x ((1 - 20%) / (1 - current rate)) to the power of the elasticity: the gains sit wholly in the basic rate band, so the marginal rates on them are the basic rates; the current rate is read from current law, at the default elasticity of 1",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pending"
+    },
+    {
+      "actual": 140.0,
+      "assertion_id": "change:capital_gains_tax:2027:4",
+      "case_id": "cgt_default_response",
+      "check": "change:capital_gains_tax:2027",
+      "decision_id": "policyengine-uk#2396",
+      "expected": 91.21951219512198,
+      "holds": false,
+      "oracle": "(realised gains - the annual exempt amount) x 20% - (\u00a310,000 of gains - the annual exempt amount) x current rate, with the realised gains above; the exempt amount and current rate are read from current law, at the default elasticity of 1",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pending"
+    },
+    {
+      "actual": 10000.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains:2027",
+      "expected": 10000.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "case_id": "cgt_default_response",
+      "check": "unreformed_after_reform:capital_gains_tax:2027",
+      "expected": 1260.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "74ad41e5df137075fc41759a886fd4f66e0ea945e1d0c207429a90ff704413cd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "cgt_default_response",
+        "reform_sha256": "b993d90de94b43bcbb2748db127c6e4f71e190bd8ff72e816eafb937eec9a9c8",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "cgt_default_response",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 13200.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 13200.0,
+      "holds": null,
+      "oracle": "ITA 2007 s57(3)",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 39600.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 39600.0,
+      "holds": null,
+      "oracle": "ITA 2007 s21(3)",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 253.85,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:2",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 253.85,
+      "holds": null,
+      "oracle": "aligned with the allowance, weekly",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "9d7a12f52e9da74f616d30f23f8a8796ee7638e39ecebb63da492de0124aa0e9",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 13200.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 13200.0,
+      "holds": null,
+      "oracle": "ITA 2007 s57(3)",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 39600.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 39600.0,
+      "holds": null,
+      "oracle": "ITA 2007 s21(3)",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 253.85,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:2",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 253.85,
+      "holds": null,
+      "oracle": "aligned with the allowance, weekly",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "september_cpi_moves_indexed_thresholds",
+        "reform_sha256": "3a203256153655059f114668934f03a8b0128524b1844c8bb72e50cb61f2f6e5",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 13200.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031:0",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "decision_id": null,
+      "expected": 13200.0,
+      "holds": null,
+      "oracle": "ITA 2007 s57(3)",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 39600.0,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031:1",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "decision_id": null,
+      "expected": 39600.0,
+      "holds": null,
+      "oracle": "ITA 2007 s21(3)",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 253.85,
+      "assertion_id": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031:2",
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "decision_id": null,
+      "expected": 253.85,
+      "holds": null,
+      "oracle": "aligned with the allowance, weekly",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 12830.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
+      "expected": 12830.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 38500.0,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
+      "expected": 38500.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 246.73,
+      "case_id": "september_cpi_moves_indexed_thresholds",
+      "check": "unreformed_after_reform:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
+      "expected": 246.73,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_LCWRA_element:2027:0",
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "variable:uc_LCWRA_element:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "442bf59ad324711999e26e687b4acb9e421a35195346a4a2297354e9f255db7d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "baseline_isolation:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "442bf59ad324711999e26e687b4acb9e421a35195346a4a2297354e9f255db7d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "442bf59ad324711999e26e687b4acb9e421a35195346a4a2297354e9f255db7d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_LCWRA_element:2027:0",
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "variable:uc_LCWRA_element:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "9d0cecf62201d525f32c2b53d0cc5950127290a4063f4f709b09fff3ea3bd140",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "baseline_isolation:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "9d0cecf62201d525f32c2b53d0cc5950127290a4063f4f709b09fff3ea3bd140",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "9d0cecf62201d525f32c2b53d0cc5950127290a4063f4f709b09fff3ea3bd140",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_LCWRA_element:2027:0",
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "variable:uc_LCWRA_element:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "baseline_isolation:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_LCWRA_element:2027:0",
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "variable:uc_LCWRA_element:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "6f085d080cf6be93434e99ae984380f8ce87bdd6beab25c1abe4f1c9c8925a77",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "6f085d080cf6be93434e99ae984380f8ce87bdd6beab25c1abe4f1c9c8925a77",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_LCWRA_element:2027:0",
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "variable:uc_LCWRA_element:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "6f085d080cf6be93434e99ae984380f8ce87bdd6beab25c1abe4f1c9c8925a77",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5259.26806640625,
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": "unreformed_after_reform:uc_LCWRA_element:2027",
+      "expected": 5259.26806640625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "uc_rebalancing_reform_after_data_load",
+        "reform_sha256": "6f085d080cf6be93434e99ae984380f8ce87bdd6beab25c1abe4f1c9c8925a77",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "uc_rebalancing_reform_after_data_load",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 1260.0,
+      "assertion_id": "variable:marriage_allowance:2026:0",
+      "case_id": "structural_switch",
+      "check": "variable:marriage_allowance:2026",
+      "decision_id": null,
+      "expected": 1260.0,
+      "holds": null,
+      "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+      "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "e683e23a1d7da5038783f3a42f3208e01d34e9d873907ad213bacb1c9ad19a37",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "baseline_isolation:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "e683e23a1d7da5038783f3a42f3208e01d34e9d873907ad213bacb1c9ad19a37",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "unreformed_after_reform:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "e683e23a1d7da5038783f3a42f3208e01d34e9d873907ad213bacb1c9ad19a37",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "assertion_id": "variable:marriage_allowance:2026:0",
+      "case_id": "structural_switch",
+      "check": "variable:marriage_allowance:2026",
+      "decision_id": null,
+      "expected": 1260.0,
+      "holds": null,
+      "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+      "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "cb0da957a89c98b056fb93513eea1742af054428b69394dfa2a86997fefc3279",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "baseline_isolation:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "cb0da957a89c98b056fb93513eea1742af054428b69394dfa2a86997fefc3279",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "unreformed_after_reform:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "cb0da957a89c98b056fb93513eea1742af054428b69394dfa2a86997fefc3279",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "assertion_id": "variable:marriage_allowance:2026:0",
+      "case_id": "structural_switch",
+      "check": "variable:marriage_allowance:2026",
+      "decision_id": null,
+      "expected": 1260.0,
+      "holds": null,
+      "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+      "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "baseline_isolation:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "unreformed_after_reform:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "assertion_id": "variable:marriage_allowance:2026:0",
+      "case_id": "structural_switch",
+      "check": "variable:marriage_allowance:2026",
+      "decision_id": null,
+      "expected": 1260.0,
+      "holds": null,
+      "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+      "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "af729310839cbeb6c27fe6d8934b8dbddd37f6d9078ee45d8381a33ee72b568e",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "unreformed_after_reform:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "af729310839cbeb6c27fe6d8934b8dbddd37f6d9078ee45d8381a33ee72b568e",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 1260.0,
+      "assertion_id": "variable:marriage_allowance:2026:0",
+      "case_id": "structural_switch",
+      "check": "variable:marriage_allowance:2026",
+      "decision_id": null,
+      "expected": 1260.0,
+      "holds": null,
+      "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
+      "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "af729310839cbeb6c27fe6d8934b8dbddd37f6d9078ee45d8381a33ee72b568e",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0,
+      "case_id": "structural_switch",
+      "check": "unreformed_after_reform:marriage_allowance:2026",
+      "expected": 0.0,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "structural_switch",
+        "reform_sha256": "af729310839cbeb6c27fe6d8934b8dbddd37f6d9078ee45d8381a33ee72b568e",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "structural_switch",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 5263.158203125,
+      "assertion_id": "baseline_equals:baseline_vat:2026:0",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_equals:baseline_vat:2026",
+      "decision_id": null,
+      "expected": 5263.158203125,
+      "holds": null,
+      "oracle": "baseline_vat is the unreformed vat",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 526.3154296875,
+      "assertion_id": "change:vat:2026:1",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "change:vat:2026",
+      "decision_id": null,
+      "expected": 526.3157894736839,
+      "holds": null,
+      "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "99683588e59cc7c52116b57f49a1f511b4598e73444272ec65538ef34e37de3a",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "assertion_id": "baseline_equals:baseline_vat:2026:0",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_equals:baseline_vat:2026",
+      "decision_id": null,
+      "expected": 5263.158203125,
+      "holds": null,
+      "oracle": "baseline_vat is the unreformed vat",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 526.3154296875,
+      "assertion_id": "change:vat:2026:1",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "change:vat:2026",
+      "decision_id": null,
+      "expected": 526.3157894736839,
+      "holds": null,
+      "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "6caf1b1b8bce09446ab445fca925df3df2f2f90dc359e64f85fd5bae417d6ba4",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "assertion_id": "baseline_equals:baseline_vat:2026:0",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_equals:baseline_vat:2026",
+      "decision_id": null,
+      "expected": 5263.158203125,
+      "holds": null,
+      "oracle": "baseline_vat is the unreformed vat",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 526.3154296875,
+      "assertion_id": "change:vat:2026:1",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "change:vat:2026",
+      "decision_id": null,
+      "expected": 526.3157894736839,
+      "holds": null,
+      "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_isolation:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "assertion_id": "baseline_equals:baseline_vat:2026:0",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_equals:baseline_vat:2026",
+      "decision_id": null,
+      "expected": 5263.158203125,
+      "holds": null,
+      "oracle": "baseline_vat is the unreformed vat",
+      "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 526.3154296875,
+      "assertion_id": "change:vat:2026:1",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "change:vat:2026",
+      "decision_id": null,
+      "expected": 526.3157894736839,
+      "holds": null,
+      "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+      "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:baseline_vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "baseline_equals:baseline_vat:2026:0",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "baseline_equals:baseline_vat:2026",
+      "reason": "the policy route's output dataset holds the reformed run only",
+      "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": 526.3154296875,
+      "assertion_id": "change:vat:2026:1",
+      "case_id": "baseline_vat_is_current_law",
+      "check": "change:vat:2026",
+      "decision_id": null,
+      "expected": 526.3157894736839,
+      "holds": null,
+      "oracle": "\u00a310,000 of full-rate consumption x (22% - current rate), over the share of consumption the microdata covers; the current rate and coverage are read from current law",
+      "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5263.158203125,
+      "case_id": "baseline_vat_is_current_law",
+      "check": "unreformed_after_reform:vat:2026",
+      "expected": 5263.158203125,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "228c864948e49f1bafb1020ecd1a6a6aab050d94c43bd4f60144d4d6074d7626",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "baseline_vat_is_current_law",
+        "reform_sha256": "0e57f240e31dc177dae06b735fd47b05f9c95894a049bf2816d3ae7f6114bb47",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "baseline_vat_is_current_law",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "5c5e53ff74dc04bfc360ff580ca1013acb39023cef9edc4ad458d73bebe035d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "05701fb7bdc19fc311b70302afe7979c1f8e5b17b9484e76d3906b11d207de83",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "e6aba941ed6d2857584bcb6323f8e4186dc97005a39b1a9f05458858523ba545",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "modifier_then_parameter_changes",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "modifier_then_parameter_changes",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fdd130c561e213b17840d484c320191f464d341cf29bb534f03aa9a846d143d5",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "9fd82d1d38614616b8ee42850e07bc6bbd018da3b7007014609714017d39a3d4",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "fcaf08431cabc68b5e0b6983a816afaa3482a7d32ef9f23deaca75753b191249",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.0875,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.0875,
+      "holds": null,
+      "oracle": "set by the modifier",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before the change",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "in force on 30 April 2027",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "baseline_isolation:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "the reformed simulation's baseline equals an unreformed simulation",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.1075,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "expected": 0.1075,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "8e7554729292ab5cb608f34d2be15d8619eefa8f492ca83e2d7c93b41e2ca3dd",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026:0",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027:1",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.dividends[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:2",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:3",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "reason": "this route exposes outputs, not parameter values",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "unsupported"
+    },
+    {
+      "actual": -190.0,
+      "assertion_id": "change:income_tax:2026:4",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2026",
+      "decision_id": null,
+      "expected": -190.00000000000003,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": -15.7001953125,
+      "assertion_id": "change:income_tax:2027:5",
+      "case_id": "parameter_changes_then_modifier",
+      "check": "change:income_tax:2027",
+      "decision_id": null,
+      "expected": -15.700000000000358,
+      "holds": null,
+      "oracle": "(\u00a310,000 of dividends - the dividend allowance) x (8.75% - current dividend rate), all within the basic rate band, plus (30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2026",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 4507.25,
+      "case_id": "parameter_changes_then_modifier",
+      "check": "unreformed_after_reform:income_tax:2027",
+      "expected": 4507.25,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "43a019779739fe68e8b656937b0ddc64095111ef68da072075d4212c17e66faf",
+      "reform_identity": null,
+      "reform_identity_unavailable": "the case's simulation modifier is a closure, which scenario_reform_identity refuses to bind",
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+      "case_id": "unknown_path",
+      "check": "rejected",
+      "expected": "an error matching 'new_credit'",
+      "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "unknown_path",
+        "reform_sha256": "a37b60f951358a9333d2ae2d68f9c50e5126fe06c7fa8d2b530f7e27ddd1e623",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+      "case_id": "unknown_path",
+      "check": "rejected",
+      "expected": "an error matching 'new_credit'",
+      "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "unknown_path",
+        "reform_sha256": "d2935e4ad6fd5c5e48e57c51bf59dfcadc6c969431ebe4d381fd4725580783db",
+        "representation": "policyengine-uk.scenario/v1"
+      },
+      "route": "country.scenario_parameter_changes",
+      "status": "pass"
+    },
+    {
+      "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
+      "case_id": "unknown_path",
+      "check": "rejected",
+      "expected": "an error matching 'new_credit'",
+      "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.130.1:\n  - 'gov.budget_2026.new_credit.amount'",
+      "case_id": "unknown_path",
+      "check": "rejected",
+      "expected": "an error matching 'new_credit'",
+      "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "unknown_path",
+        "reform_sha256": "6b1d9cc2b45966b2ef37950ad39d708644e376e9a203b158d004a73d0df66b85",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.130.1:\n  - 'gov.budget_2026.new_credit.amount'",
+      "case_id": "unknown_path",
+      "check": "rejected",
+      "expected": "an error matching 'new_credit'",
+      "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "unknown_path",
+        "reform_sha256": "6b1d9cc2b45966b2ef37950ad39d708644e376e9a203b158d004a73d0df66b85",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "case_id": "unknown_path",
+      "check": null,
+      "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "the route does not run in-process",
+      "route": "api.sim_api",
+      "status": "unsupported"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "reading_bare_year_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "fiscal year 2027",
+      "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_bare_year_dict",
+        "reform_sha256": "a17ad3d70916d16416c1181d6f7e83b43c6736908f321e0984abdef8df0fe81d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "reading_bare_year_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "that year only",
+      "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_bare_year_dict",
+        "reform_sha256": "a17ad3d70916d16416c1181d6f7e83b43c6736908f321e0984abdef8df0fe81d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_bare_year_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_bare_year_dict",
+        "reform_sha256": "a17ad3d70916d16416c1181d6f7e83b43c6736908f321e0984abdef8df0fe81d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_bare_year_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_bare_year_dict",
+        "reform_sha256": "a17ad3d70916d16416c1181d6f7e83b43c6736908f321e0984abdef8df0fe81d",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026:0",
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "before 1 January 2027",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:1",
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "from 1 January 2027",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.21,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:2",
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.21,
+      "holds": null,
+      "oracle": "onwards",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2026",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_bare_year_reform_from_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
+      "reform_identity": null,
+      "reform_identity_unavailable": "receipt schema v1 has no representation for what country.reform_from_dict consumes",
+      "route": "country.reform_from_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027:0",
+      "case_id": "reading_single_day_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "one day is not 30 April",
+      "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_single_day_dict",
+        "reform_sha256": "f576ac6d74b8e3dc782eaeeb81b6254e76baa72546eac3ab2adec7a6052f9174",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "assertion_id": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028:1",
+      "case_id": "reading_single_day_dict",
+      "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "decision_id": null,
+      "expected": 0.2,
+      "holds": null,
+      "oracle": "one day only",
+      "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_single_day_dict",
+        "reform_sha256": "f576ac6d74b8e3dc782eaeeb81b6254e76baa72546eac3ab2adec7a6052f9174",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_single_day_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2027",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_single_day_dict",
+        "reform_sha256": "f576ac6d74b8e3dc782eaeeb81b6254e76baa72546eac3ab2adec7a6052f9174",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 0.2,
+      "case_id": "reading_single_day_dict",
+      "check": "unreformed_after_reform:gov.hmrc.income_tax.rates.uk[0].rate:2028",
+      "expected": 0.2,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_single_day_dict",
+        "reform_sha256": "f576ac6d74b8e3dc782eaeeb81b6254e76baa72546eac3ab2adec7a6052f9174",
+        "representation": "policyengine-uk.reform_dict/v1"
+      },
+      "route": "country.reform_dict",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.household",
+      "status": "pass"
+    },
+    {
+      "actual": 6000.0,
+      "assertion_id": "variable:uc_standard_allowance:2027:0",
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "variable:uc_standard_allowance:2027",
+      "decision_id": null,
+      "expected": 6000.0,
+      "holds": null,
+      "oracle": "\u00a3500 x 12",
+      "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 6240.0,
+      "assertion_id": "variable:uc_standard_allowance:2028:1",
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "variable:uc_standard_allowance:2028",
+      "decision_id": null,
+      "expected": 6240.0,
+      "holds": null,
+      "oracle": "\u00a3520 x 12",
+      "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5216.06103515625,
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "unreformed_after_reform:uc_standard_allowance:2027",
+      "expected": 5216.06103515625,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": 5320.3740234375,
+      "case_id": "reading_effective_dates_reverse_order",
+      "check": "unreformed_after_reform:uc_standard_allowance:2028",
+      "expected": 5320.3740234375,
+      "oracle": "an unreformed simulation built after the reform equals one built before it",
+      "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
+      "reform_identity": {
+        "binding": "content",
+        "kind": "reform",
+        "name": "reading_effective_dates_reverse_order",
+        "reform_sha256": "fa2c95313ac6daa569395bf1b5d8595d5399731158ad6b5132641f0e3eac983c",
+        "representation": "policyengine.reform_dict/v1"
+      },
+      "route": "wrapper.policy",
+      "status": "pass"
+    },
+    {
+      "actual": "unchanged",
+      "case_id": "module_parameters_unchanged",
+      "check": "every parameter's dated values and metadata, and every node's metadata and band order, in processed, projected, statutory, system",
+      "expected": "policyengine-uk's shared parameters as they were before the run",
+      "oracle": "the shared parameter state's values, read before any reform ran",
+      "reform_digest": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "a run-level row runs no reform",
+      "route": "all",
+      "status": "pass"
+    }
+  ],
+  "contract_id": "policyengine-uk/budget-reform-contract",
+  "contract_version": "1.1.0",
+  "dataset": {
+    "path": "",
+    "sha256": "056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784"
+  },
+  "holds": true,
+  "max_examples": 20,
+  "population": [
+    {
+      "check_id": "population_baseline_isolation",
+      "detail": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_baseline_isolation",
+      "detail": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_baseline_isolation",
+      "detail": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_baseline_isolation",
+      "detail": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "unreformed",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_query_order",
+      "detail": null,
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "unreformed",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_routes_agree",
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict = country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_routes_agree",
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict = country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_april_rate_change",
+      "detail": {
+        "2026_unchanged": true,
+        "2027_people_with_higher_tax": 1093,
+        "2027_people_with_lower_tax": 4,
+        "2027_total_change": 205573.0608100891
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_april_rate_change",
+      "detail": {
+        "2026_unchanged": true,
+        "2027_people_with_higher_tax": 1093,
+        "2027_people_with_lower_tax": 4,
+        "2027_total_change": 205573.0608100891
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_april_rate_change",
+      "detail": {
+        "2026_unchanged": true,
+        "2027_people_with_higher_tax": 1093,
+        "2027_people_with_lower_tax": 4,
+        "2027_total_change": 205573.0608100891
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_finite_change_expires",
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_finite_change_expires",
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_finite_change_expires",
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_uc_standard_allowance_plus_10",
+      "detail": {
+        "awards_lower": 0,
+        "payments_below_the_payable_floor": 0,
+        "payments_higher": 102,
+        "payments_lower": 1,
+        "payments_not_award_less_deductions": 0,
+        "standard_allowance_scaled_10_percent": true,
+        "units_with_non_finite_values": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_uc_standard_allowance_plus_10",
+      "detail": {
+        "awards_lower": 0,
+        "payments_below_the_payable_floor": 0,
+        "payments_higher": 102,
+        "payments_lower": 1,
+        "payments_not_award_less_deductions": 0,
+        "standard_allowance_scaled_10_percent": true,
+        "units_with_non_finite_values": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_uc_standard_allowance_plus_10",
+      "detail": {
+        "awards_lower": 0,
+        "payments_below_the_payable_floor": 0,
+        "payments_higher": 102,
+        "payments_lower": 1,
+        "payments_not_award_less_deductions": 0,
+        "standard_allowance_scaled_10_percent": true,
+        "units_with_non_finite_values": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_state_pension_plus_10",
+      "detail": {
+        "basic_and_new_scaled_10_percent": true,
+        "pensions_higher": 507,
+        "pensions_lower": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_state_pension_plus_10",
+      "detail": {
+        "basic_and_new_scaled_10_percent": true,
+        "pensions_higher": 507,
+        "pensions_lower": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.scenario_parameter_changes",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    },
+    {
+      "check_id": "population_state_pension_plus_10",
+      "detail": {
+        "basic_and_new_scaled_10_percent": true,
+        "pensions_higher": 507,
+        "pensions_lower": 0
+      },
+      "reform_identity": null,
+      "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+      "route": "country.reform_from_dict",
+      "seed": 0,
+      "status": "pass",
+      "subsample_households": 1000
+    }
+  ],
+  "prior_law_option": "projected",
+  "properties": [
+    {
+      "engine": "hypothesis",
+      "examples_run": 20,
+      "property_id": "annual_values_match_the_oracle",
+      "reform_identity": null,
+      "reform_identity_unavailable": "a sampled property runs many sampled reforms, so its row binds none",
+      "status": "pass"
+    },
+    {
+      "engine": "hypothesis",
+      "examples_run": 20,
+      "property_id": "routes_agree_and_baselines_hold",
+      "reform_identity": null,
+      "reform_identity_unavailable": "a sampled property runs many sampled reforms, so its row binds none",
+      "status": "pass"
+    }
+  ],
+  "routes": [
+    "country.reform_dict",
+    "country.scenario_parameter_changes",
+    "country.reform_from_dict",
+    "wrapper.household",
+    "wrapper.policy",
+    "api.sim_api"
+  ],
+  "seed": 0,
+  "summary": {
+    "error": 0,
+    "fail": 0,
+    "pass": 792,
+    "pending": 25,
+    "unsupported": 101
+  },
+  "versions": {
+    "policyengine": "6.4.0",
+    "policyengine-core": "3.33.0",
+    "policyengine-uk": "2.130.1"
+  }
+}
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 5c2efa26..ab0f7685 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -559,27 +559,6 @@ def _declared_coverage(source):
     by_case = {}
     for row in source.get("cases") or []:
         by_case.setdefault(row.get("case_id"), []).append(row)
-    # A historical report came from a runner whose oracle wording may differ
-    # from today's. Checks sharing a label are told apart by oracle, so
-    # declare them as that runner did: one reworded declaration takes the one
-    # recorded oracle no current declaration matches.
-    for (case_id, *label), checks in declared_checks.items():
-        check_label = ":".join(str(part) for part in label)
-        recorded = {
-            row.get("oracle")
-            for row in by_case.get(case_id, ())
-            if row.get("check") == check_label and row.get("oracle") is not None
-        }
-        current = {getattr(check, "oracle", None) for check in checks}
-        reworded = [check for check in checks if check.oracle not in recorded]
-        unmatched = recorded - current
-        if len(checks) > 1 and len(reworded) == 1 and len(unmatched) == 1:
-            declared_checks[(case_id, *label)] = [
-                SimpleNamespace(**{**vars(check), "oracle": next(iter(unmatched))})
-                if check is reworded[0]
-                else check
-                for check in checks
-            ]
     return {
         "ROUTES": tuple(source.get("routes") or ()),
         "CASES": tuple(
@@ -797,7 +776,7 @@ def test_no_contract_configured_is_unavailable():
 
 
 CONTRACT_FIXTURES = Path(__file__).parent / "fixtures" / "uk_contract"
-CERTIFIED_SHA = "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
+CERTIFIED_SHA = "056e80fd8e9151d78f432a25cde863340baee81304c6216a37fb575ce8563784"
 STATUS_RANK = {"pass": 0, "error": 1, "fail": 2}
 
 
@@ -818,9 +797,10 @@ def _recount(report: dict) -> dict:
 
 
 def _passing_report() -> dict:
-    """W1's real full run: every route, 20 examples, the certified dataset."""
+    """A real full run of the runner: every route, 20 examples, the certified
+    pair and dataset."""
 
-    return _fixture("full_released_uk_2.126.12.json")
+    return _fixture("full_released_uk_2.130.1.json")
 
 
 def _run_contract(
@@ -851,9 +831,11 @@ def _run_released_contract(report, *, pending_decisions=()):
     from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
 
     if runner.CONTRACT_VERSION != report["contract_version"]:
-        pytest.skip(
-            f"the runner declares contract {runner.CONTRACT_VERSION}; refresh "
-            "tests/fixtures/uk_contract with a real full run"
+        # Round 9 of #574: skipping hid a gate that rejected every real run.
+        pytest.fail(
+            f"the runner declares contract {runner.CONTRACT_VERSION}, the fixture "
+            f"{report['contract_version']}: refresh tests/fixtures/uk_contract "
+            "with a real full run of the runner"
         )
     proxy = types.ModuleType(runner.__name__)
     proxy.__dict__.update(vars(runner))
@@ -877,20 +859,20 @@ def importer(name):
 def test_the_released_models_full_run_passes_the_runners_own_declarations():
     """W1's full run remains valid against the real runner's declarations."""
 
-    result = _run_released_contract(_fixture("full_released_uk_2.126.12.json"))
+    result = _run_released_contract(_fixture("full_released_uk_2.130.1.json"))
     assert result.status == "pass", result.summary
     assert result.details["counts"] == {
-        "pass": 673,
+        "pass": 792,
         "fail": 0,
         "error": 0,
-        "unsupported": 79,
-        "pending": 6,
+        "unsupported": 101,
+        "pending": 25,
     }
 
 
 @pytest.mark.parametrize("section", ["cases", "population"])
 def test_supported_failures_cannot_be_relabelled_unsupported(section):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report[section]
@@ -907,7 +889,7 @@ def test_supported_failures_cannot_be_relabelled_unsupported(section):
 
 
 def test_population_cannot_exempt_every_required_check():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     assert len(report["population"]) == 19
     for row in report["population"]:
         row.update(status="unsupported", reason="no population support")
@@ -921,7 +903,7 @@ def test_population_cannot_exempt_every_required_check():
 
 @pytest.mark.parametrize("row_index", range(19))
 def test_each_population_route_row_is_required(row_index):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     omitted = report["population"].pop(row_index)
     result = _run_released_contract(_recount(report))
     assert result.status == "error", result.summary
@@ -932,7 +914,7 @@ def test_each_population_route_row_is_required(row_index):
 
 
 def test_deleting_a_failed_uc_population_route_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     omitted = next(
         row
         for row in report["population"]
@@ -955,7 +937,7 @@ def test_deleting_a_failed_uc_population_route_cannot_qualify():
     ],
 )
 def test_population_assertion_cannot_borrow_a_case_pending_decision(override, check_id):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(row for row in report["population"] if row["check_id"] == check_id)
     row["status"] = "fail"
     assert _run_released_contract(_recount(report)).status == "fail"
@@ -968,7 +950,7 @@ def test_population_assertion_cannot_borrow_a_case_pending_decision(override, ch
 
 
 def test_one_population_row_per_check_id_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     report["population"] = list(
         {row["check_id"]: row for row in report["population"]}.values()
     )
@@ -977,13 +959,13 @@ def test_one_population_row_per_check_id_cannot_qualify():
 
 
 def test_duplicate_population_route_cannot_replace_another_route():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     report["population"][1] = dict(report["population"][0])
     assert _run_released_contract(_recount(report)).status == "error"
 
 
 def test_an_unknown_assertion_identity_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report["cases"]
@@ -999,13 +981,17 @@ def test_an_unknown_assertion_identity_cannot_qualify():
 
 @pytest.mark.parametrize("override", [(), ("d1344",)])
 def test_mandatory_freeze_assertion_cannot_borrow_pending_authorization(override):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report["cases"]
         if row["case_id"] == "extended_freeze"
         and row["route"] == "country.reform_dict"
-        and row.get("oracle") == "contract 1.0.0: prior law's projected path resumes"
+        and row.get("check")
+        == "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034"
+        # The mandatory one of the two 2034 checks (the other awaits d1344).
+        and row["status"] == "pass"
+        and row.get("decision_id") is None
     )
     row["status"] = "fail"
     assert _run_released_contract(_recount(report)).status == "fail"
@@ -1016,7 +1002,7 @@ def test_mandatory_freeze_assertion_cannot_borrow_pending_authorization(override
 
 
 def test_swapping_mandatory_and_pending_freeze_statuses_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     rows = [
         row
         for row in report["cases"]
@@ -1035,7 +1021,7 @@ def test_swapping_mandatory_and_pending_freeze_statuses_cannot_qualify():
 
 @pytest.mark.parametrize("replace_status", ["pass", "pending"])
 def test_duplicate_freeze_assertion_cannot_satisfy_the_other_category(replace_status):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     matching = [
         row
         for row in report["cases"]
@@ -1056,7 +1042,7 @@ def test_duplicate_freeze_assertion_cannot_satisfy_the_other_category(replace_st
 
 @pytest.mark.parametrize("route", ["api.sim_api", "wrapper.household"])
 def test_declared_case_exemptions_require_the_runners_reason(route):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report["cases"]
@@ -1068,8 +1054,36 @@ def test_declared_case_exemptions_require_the_runners_reason(route):
     assert any("different reason" in p for p in result.details["problems"])
 
 
+def test_the_runners_own_run_level_row_is_recognised():
+    """Round 9 of #574: contract 1.1.0 reworded the shared parameter check,
+    and a gate fixed to the 1.0.0 wording rejected every candidate. The row
+    the installed runner emits must pass; an unrelated check must not."""
+
+    from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
+
+    def gated(check):
+        report = _passing_report()
+        row = next(
+            row
+            for row in report["cases"]
+            if row["case_id"] == "module_parameters_unchanged"
+        )
+        row["check"] = check
+        return _run_contract(report)
+
+    current = runner.module_parameters_unchanged(runner.shared_state())
+    assert current["status"] == "pass"
+    assert gated(current["check"]).status == "pass", gated(current["check"]).summary
+    unrelated = gated("every case's reform digest in policyengine-uk")
+    assert unrelated.status == "error"
+    assert any(
+        "does not identify the shared parameter check" in problem
+        for problem in unrelated.details["problems"]
+    )
+
+
 def test_deleting_a_failed_run_level_check_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report["cases"]
@@ -1098,7 +1112,7 @@ def test_deleting_a_failed_run_level_check_cannot_qualify():
     ],
 )
 def test_each_runner_isolation_row_is_required(route, check_prefix):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     omitted = next(
         row
         for row in report["cases"]
@@ -1111,7 +1125,7 @@ def test_each_runner_isolation_row_is_required(route, check_prefix):
 
 
 def test_deleting_all_runner_isolation_rows_cannot_qualify():
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     report["cases"] = [
         row
         for row in report["cases"]
@@ -1128,7 +1142,7 @@ def test_deleting_all_runner_isolation_rows_cannot_qualify():
     "check_prefix", ["baseline_isolation:", "unreformed_after_reform:"]
 )
 def test_failing_isolation_checks_cannot_be_relabelled_pending(check_prefix):
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     row = next(
         row
         for row in report["cases"]
@@ -1181,12 +1195,13 @@ def test_w1_population_run_alone_is_incomplete():
 
 
 def test_w1_full_run_passes():
-    """W1's real all-pass report: 673 pass, 6 pending d1344, 79 unsupported."""
+    """The real full run of contract 1.1.0 on the certified pair: 792 pass,
+    25 pending a methodology call, 101 unsupported by design."""
 
     result = _run_contract(_passing_report())
     assert result.status == "pass", result.summary
-    assert "every case, property and population check passed (673)" in result.summary
-    assert "6 pending a methodology call" in result.summary
+    assert "every case, property and population check passed (792)" in result.summary
+    assert "25 pending a methodology call" in result.summary
     assert result.details["problems"] == []
 
 
@@ -1303,7 +1318,7 @@ def test_new_population_route_declaration_is_required_without_a_gate_side_list(
         "population_check_routes",
         lambda routes: (*declared(routes), ("new_population_check", "unreformed")),
     )
-    report = _fixture("full_released_uk_2.126.12.json")
+    report = _fixture("full_released_uk_2.130.1.json")
     result = _run_released_contract(report)
     assert result.status == "error", result.summary
     assert any(

From 892d8dab42a5fa6597ffc5ec804dea1808c98423 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 01:13:14 -0400
Subject: [PATCH 36/45] Replace the 1.58.0 metrics fixture with W3's suppressed
 1.58.1 report

The 1.58.0 report predates the tool's small-cell rule and published
Disabled Students' Allowance's total and caseload, which come from
fewer than 10 records, unsuppressed; totals containing it gave it back.
The 1.58.1 report at tool commit 228a05a3e publishes those figures as
suppressed and rebuilds every total without them.

The gate and tests that read the report move to the suppression format
in the next commit. History is left as is pending a security decision.

Co-Authored-By: Claude Opus 5.5 
---
 tests/fixtures/uk_metrics/README.md           |   35 +-
 .../uk_metrics/budget_metrics_report.json     | 5692 +++++++++++++----
 2 files changed, 4538 insertions(+), 1189 deletions(-)

diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index f438a64c..3a26ba33 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -1,24 +1,27 @@
 # UK metrics tool fixtures
 
 Both files come from PolicyEngine/policyengine-uk's aggregate-impact tool
-(`policyengine_uk/utils/aggregate_impact/`, policyengine-uk#2335), which the
-qualification config pins at commit
-`9b33fe19f80676fc5b81d2d80b36072e1c2fc1df`. They were produced at its parent,
-`bd8bff74c0baea19c09eedf9ce1391d598d2ffaf`; the pinned commit changes only
-when the tool digest is taken (at module load rather than at the end of a
-run), so `standard_reforms.yaml` is byte-identical there and the report format
-is unchanged. A report from the pinned commit differs only in
-`metrics_version`, which the gate compares between the two pairs' reports,
-never against this file. `tests/test_uk_candidate_gates.py` reads them.
-Refresh them when a pin changes the report; never edit them by hand.
+(`policyengine_uk/utils/aggregate_impact/`, policyengine-uk#2335).
+`tests/test_uk_candidate_gates.py` reads them. Refresh them when a pin changes
+the report; never edit them by hand.
 
+- `budget_metrics_report.json`: a real `compute_budget_metrics` report from
+  the tool's owner (workstream W3), at tool commit
+  `228a05a3e925beb50da619aa01e68c266e578fc0`, on the certified pair: uk-data
+  1.58.1 (`enhanced_frs_2024_25`) with policyengine-uk 2.130.1 and
+  policyengine-core 3.33.0, for 2025-26 to 2031-32, with the overlap guard and
+  the ten standard reforms. It holds aggregates only, under the tool's
+  small-cell rule (`privacy.py`): a figure from fewer than 10 records is
+  published as `value` null with `suppressed` true, and every total that
+  holds one is rebuilt without it and lists it under `excludes`. It has
+  1,484 metric rows (14 suppressed: Disabled Students' Allowance's total and
+  caseload in each of the seven years) and 350 checks.
 - `standard_reforms.yaml`: the tool's standard reform set, copied unchanged.
   Ten reforms, each with the model variable it must move, the direction and
   the least it must move it in every year. The reform responsiveness gate
   reads the same file from the vendored tool.
-- `budget_metrics_report.json`: a real `compute_budget_metrics` report from
-  the tool's owner (workstream W3), run on 11 October 2026 at the pinned tool
-  commit on uk-data 1.58.0 (`enhanced_frs_2024_25`) with policyengine-uk main,
-  for 2025-26 to 2031-32, with the overlap guard and the ten standard reforms.
-  It holds aggregates only: 1,470 metric rows and 346 checks (327 pass,
-  15 warn, 4 fail), each check with its `failing_scopes`.
+
+This report replaces a 1.58.0 report from before the tool suppressed small
+cells. That report published Disabled Students' Allowance, which comes from
+fewer than 10 records, unsuppressed. Never commit a report from a tool
+commit that predates suppression.
diff --git a/tests/fixtures/uk_metrics/budget_metrics_report.json b/tests/fixtures/uk_metrics/budget_metrics_report.json
index 6b599fb5..76fc0733 100644
--- a/tests/fixtures/uk_metrics/budget_metrics_report.json
+++ b/tests/fixtures/uk_metrics/budget_metrics_report.json
@@ -1,8 +1,8 @@
 {
  "schema": "policyengine-uk-aggregate-impact/1/report",
  "status": "ok",
- "metrics_version": "policyengine-uk-aggregate-impact/1+3d0c53d5b453bd14+bf81c943e4ebec5a",
- "partition_version": "779be6fce5878c1a358e1d921e4427cae51b2cb9391dabf923b5c624ae2d1070",
+ "metrics_version": "policyengine-uk-aggregate-impact/1+47b285096857148a+bb5198a0d8e7c046",
+ "partition_version": "e8ea8a0198736e7cd9b0725148fdda717911033ee768eba044b58a8d46e9b0ef",
  "years": [
   2025,
   2026,
@@ -16,7 +16,9 @@
   {
    "metric_id": "population.person",
    "year": 2025,
-   "value": 69712844.3129216,
+   "value": 69513955.15348345,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -25,7 +27,9 @@
   {
    "metric_id": "population.person",
    "year": 2026,
-   "value": 69977755.64010108,
+   "value": 69778110.5666471,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -34,7 +38,9 @@
   {
    "metric_id": "population.person",
    "year": 2027,
-   "value": 70236674.50701487,
+   "value": 70036290.77594277,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -43,7 +49,9 @@
   {
    "metric_id": "population.person",
    "year": 2028,
-   "value": 70517617.61980712,
+   "value": 70316432.3587328,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -52,7 +60,9 @@
   {
    "metric_id": "population.person",
    "year": 2029,
-   "value": 70827896.20421527,
+   "value": 70625825.64596106,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -61,7 +71,9 @@
   {
    "metric_id": "population.person",
    "year": 2030,
-   "value": 71146624.04218265,
+   "value": 70943644.05542476,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -70,7 +82,9 @@
   {
    "metric_id": "population.person",
    "year": 2031,
-   "value": 71452690.09232165,
+   "value": 71248701.50975493,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -79,7 +93,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2025,
-   "value": 35436904.67127848,
+   "value": 35246926.333675,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -88,7 +104,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2026,
-   "value": 35571566.183018014,
+   "value": 35380865.871866405,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -97,7 +115,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2027,
-   "value": 35703181.570698276,
+   "value": 35511775.69777489,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -106,7 +126,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2028,
-   "value": 35845992.467239186,
+   "value": 35653820.972568765,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -115,7 +137,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2029,
-   "value": 36003715.37718047,
+   "value": 35810698.281318754,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -124,7 +148,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2030,
-   "value": 36165733.258539036,
+   "value": 35971847.531772316,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -133,7 +159,9 @@
   {
    "metric_id": "population.benunit",
    "year": 2031,
-   "value": 36321314.823288456,
+   "value": 36126526.36007868,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -142,7 +170,9 @@
   {
    "metric_id": "population.household",
    "year": 2025,
-   "value": 31245113.389789984,
+   "value": 31166694.04532416,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -151,7 +181,9 @@
   {
    "metric_id": "population.household",
    "year": 2026,
-   "value": 31363845.951987505,
+   "value": 31285128.558958113,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -160,7 +192,9 @@
   {
    "metric_id": "population.household",
    "year": 2027,
-   "value": 31479892.706091657,
+   "value": 31400884.081961572,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -169,7 +203,9 @@
   {
    "metric_id": "population.household",
    "year": 2028,
-   "value": 31605810.66237679,
+   "value": 31526486.005968377,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -178,7 +214,9 @@
   {
    "metric_id": "population.household",
    "year": 2029,
-   "value": 31744876.701983795,
+   "value": 31665202.984048083,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -187,7 +225,9 @@
   {
    "metric_id": "population.household",
    "year": 2030,
-   "value": 31887729.66803205,
+   "value": 31807697.37639664,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -196,7 +236,9 @@
   {
    "metric_id": "population.household",
    "year": 2031,
-   "value": 32024907.664337814,
+   "value": 31944470.379216716,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -205,7 +247,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2025,
-   "value": 300493514624.05597,
+   "value": 297984459607.39465,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -214,7 +258,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2026,
-   "value": 320544520884.17847,
+   "value": 317782510223.38354,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -223,7 +269,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2027,
-   "value": 338021251015.9257,
+   "value": 335140035823.943,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -232,7 +280,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2028,
-   "value": 353227552195.2491,
+   "value": 350031424626.733,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -241,7 +291,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2029,
-   "value": 369117767213.9463,
+   "value": 366458443148.21484,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -250,7 +302,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2030,
-   "value": 387232407347.2469,
+   "value": 384662297800.91766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -259,7 +313,9 @@
   {
    "metric_id": "receipts.income_tax",
    "year": 2031,
-   "value": 411429752919.1772,
+   "value": 403275325039.3891,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -268,7 +324,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2025,
-   "value": 53131882407.61014,
+   "value": 52575017190.03174,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -277,7 +335,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2026,
-   "value": 55499684495.07545,
+   "value": 54941380589.82846,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -286,7 +346,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2027,
-   "value": 57316093047.9056,
+   "value": 56752394914.42203,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -295,7 +357,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2028,
-   "value": 59021168416.7411,
+   "value": 58476221815.846825,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -304,7 +368,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2029,
-   "value": 60933744650.36868,
+   "value": 60511486452.76118,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -313,7 +379,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2030,
-   "value": 62865473690.570404,
+   "value": 62445204124.271996,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -322,7 +390,9 @@
   {
    "metric_id": "receipts.nics_individual",
    "year": 2031,
-   "value": 65321678070.619606,
+   "value": 64898705801.9577,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -331,7 +401,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2025,
-   "value": 154541037552.12073,
+   "value": 152640935215.8076,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -340,7 +412,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2026,
-   "value": 161154088343.2087,
+   "value": 159182492481.57574,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -349,7 +423,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2027,
-   "value": 166167835008.01767,
+   "value": 164141628899.95114,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -358,7 +434,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2028,
-   "value": 170808399523.67877,
+   "value": 168731462725.2504,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -367,7 +445,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2029,
-   "value": 177113429874.5147,
+   "value": 175566267043.68347,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -376,7 +456,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2030,
-   "value": 182684601617.84186,
+   "value": 181079291564.9595,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -385,7 +467,9 @@
   {
    "metric_id": "receipts.nics_employer",
    "year": 2031,
-   "value": 189883460588.0551,
+   "value": 188223742975.49728,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -395,6 +479,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -404,6 +490,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -413,6 +501,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -422,6 +512,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -431,6 +523,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -440,6 +534,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -449,6 +545,8 @@
    "metric_id": "receipts.employer_nics_response_capital",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -458,6 +556,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -467,6 +567,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -476,6 +578,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -485,6 +589,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -494,6 +600,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -503,6 +611,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -512,6 +622,8 @@
    "metric_id": "receipts.employer_nics_response_consumer",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -520,7 +632,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2025,
-   "value": 12717206634.11718,
+   "value": 12618588087.194477,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -529,7 +643,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2026,
-   "value": 13157373776.93752,
+   "value": 13055343054.272093,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -538,7 +654,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2027,
-   "value": 13652775596.971504,
+   "value": 13547024733.440294,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -547,7 +665,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2028,
-   "value": 14151592611.504883,
+   "value": 14041998268.40096,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -556,7 +676,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2029,
-   "value": 14653801672.085384,
+   "value": 14540347118.814587,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -565,7 +687,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2030,
-   "value": 15204600241.922672,
+   "value": 15086908668.221151,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -574,7 +698,9 @@
   {
    "metric_id": "receipts.capital_gains_tax",
    "year": 2031,
-   "value": 15768244652.787172,
+   "value": 15645569134.728756,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -583,7 +709,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2025,
-   "value": 7830274125.077207,
+   "value": 7826615852.272217,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -592,7 +720,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2026,
-   "value": 8127270450.824548,
+   "value": 8123473394.454311,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -601,7 +731,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2027,
-   "value": 8353117705.791328,
+   "value": 8349215176.222883,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -610,7 +742,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2028,
-   "value": 8562646845.026996,
+   "value": 8558646443.275475,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -619,7 +753,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2029,
-   "value": 8789529758.204428,
+   "value": 8785423316.325344,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -628,7 +764,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2030,
-   "value": 9040980903.523558,
+   "value": 9036756985.870995,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -637,7 +775,9 @@
   {
    "metric_id": "receipts.student_loan_repayments",
    "year": 2031,
-   "value": 8059998166.851627,
+   "value": 9376925443.173416,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -646,7 +786,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2025,
-   "value": 317136171663.45935,
+   "value": 313127412006.5256,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -655,7 +797,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2026,
-   "value": 325663150441.0445,
+   "value": 321546605195.24274,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -664,7 +808,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2027,
-   "value": 333405472036.0278,
+   "value": 329191061310.5304,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -673,7 +819,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2028,
-   "value": 341433856818.8758,
+   "value": 337117963034.16547,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -682,7 +830,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2029,
-   "value": 349794893731.6442,
+   "value": 345373312536.52356,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -691,7 +841,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2030,
-   "value": 358396364144.5514,
+   "value": 353866055269.635,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -700,7 +852,9 @@
   {
    "metric_id": "receipts.vat",
    "year": 2031,
-   "value": 367137164287.62054,
+   "value": 362495430544.1016,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -710,6 +864,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -719,6 +875,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -728,6 +886,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -737,6 +897,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -746,6 +908,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -755,6 +919,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -764,6 +930,8 @@
    "metric_id": "receipts.vat_change",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -773,6 +941,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -782,6 +952,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -791,6 +963,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -800,6 +974,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -809,6 +985,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -818,6 +996,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -827,6 +1007,8 @@
    "metric_id": "receipts.private_school_vat",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -835,7 +1017,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2025,
-   "value": 24041873879.224743,
+   "value": 24534379561.8306,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -844,7 +1028,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2026,
-   "value": 24144661501.69051,
+   "value": 24639271891.62144,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -853,7 +1039,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2027,
-   "value": 26103457396.62795,
+   "value": 26638194760.36437,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -862,7 +1050,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2028,
-   "value": 26158807847.977238,
+   "value": 26694679049.418755,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -871,7 +1061,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2029,
-   "value": 25887798204.586216,
+   "value": 26418117577.300167,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -880,7 +1072,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2030,
-   "value": 25243234770.62697,
+   "value": 25760349910.6802,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -889,7 +1083,9 @@
   {
    "metric_id": "receipts.fuel_duty",
    "year": 2031,
-   "value": 25824982812.576405,
+   "value": 26353950047.77822,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -899,6 +1095,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -908,6 +1106,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -917,6 +1117,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -926,6 +1128,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -935,6 +1139,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -944,6 +1150,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -953,6 +1161,8 @@
    "metric_id": "receipts.alcohol_duty",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -962,6 +1172,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -971,6 +1183,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -980,6 +1194,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -989,6 +1205,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -998,6 +1216,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1007,6 +1227,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1016,6 +1238,8 @@
    "metric_id": "receipts.tobacco_duty",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1025,6 +1249,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1034,6 +1260,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1043,6 +1271,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1052,6 +1282,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1061,6 +1293,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1070,6 +1304,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1079,6 +1315,8 @@
    "metric_id": "receipts.vehicle_excise_duty",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1087,7 +1325,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2025,
-   "value": 4306586174.401852,
+   "value": 4275969952.7872777,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1096,7 +1336,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2026,
-   "value": 4459282492.68721,
+   "value": 4427595383.179631,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1105,7 +1347,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2027,
-   "value": 4476138521.654851,
+   "value": 4444328769.554615,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1114,7 +1358,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2028,
-   "value": 4496883532.289182,
+   "value": 4464697036.417519,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1123,7 +1369,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2029,
-   "value": 4517653126.548064,
+   "value": 4485128769.03225,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1132,7 +1380,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2030,
-   "value": 4538717337.874185,
+   "value": 4506096907.015281,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1141,7 +1391,9 @@
   {
    "metric_id": "receipts.tv_licence",
    "year": 2031,
-   "value": 4613696461.117936,
+   "value": 4526586455.751576,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1150,7 +1402,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2025,
-   "value": 49771708157.89493,
+   "value": 49560513009.82745,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1159,7 +1413,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2026,
-   "value": 52672603769.35538,
+   "value": 52449635526.310104,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1168,7 +1424,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2027,
-   "value": 56014381640.763115,
+   "value": 55778039679.1455,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1177,7 +1435,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2028,
-   "value": 59637347359.69022,
+   "value": 59386561832.62195,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1186,7 +1446,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2029,
-   "value": 63246644418.46654,
+   "value": 62981354541.126625,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1195,7 +1457,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2030,
-   "value": 67017263920.12569,
+   "value": 66736811407.45229,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1204,7 +1468,9 @@
   {
    "metric_id": "receipts.council_tax",
    "year": 2031,
-   "value": 67305565868.62192,
+   "value": 70704732540.45876,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1214,6 +1480,8 @@
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1223,6 +1491,8 @@
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1232,6 +1502,8 @@
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1240,7 +1512,9 @@
   {
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2028,
-   "value": 493860763.3252144,
+   "value": 483900104.6233177,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1249,7 +1523,9 @@
   {
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2029,
-   "value": 505953941.79338336,
+   "value": 495749379.82161856,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1258,7 +1534,9 @@
   {
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2030,
-   "value": 518394260.7963829,
+   "value": 507938784.7696847,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1267,7 +1545,9 @@
   {
    "metric_id": "receipts.high_value_council_tax_surcharge",
    "year": 2031,
-   "value": 531037020.5527634,
+   "value": 520325557.6779943,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1276,7 +1556,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2025,
-   "value": 584068659.0970445,
+   "value": 552492559.6753057,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1285,7 +1567,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2026,
-   "value": 611674416.437277,
+   "value": 578605888.7461181,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1294,7 +1578,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2027,
-   "value": 640521131.9170634,
+   "value": 605893088.8719264,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1303,7 +1589,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2028,
-   "value": 670928666.9686946,
+   "value": 634656724.1676605,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1312,7 +1600,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2029,
-   "value": 703059797.6875113,
+   "value": 665050775.6261593,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1321,7 +1611,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2030,
-   "value": 736803086.5428002,
+   "value": 696969823.2250919,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1330,7 +1622,9 @@
   {
    "metric_id": "receipts.domestic_rates",
    "year": 2031,
-   "value": 739972742.2779194,
+   "value": 730275344.6123755,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1339,7 +1633,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2025,
-   "value": 31732500424.943848,
+   "value": 31732501414.791157,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1348,7 +1644,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2026,
-   "value": 31732499121.74478,
+   "value": 31732500125.540802,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1357,7 +1655,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2027,
-   "value": 31732496311.19231,
+   "value": 31732498126.72371,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1366,7 +1666,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2028,
-   "value": 31732499335.602257,
+   "value": 31732499316.105175,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1375,7 +1677,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2029,
-   "value": 31732495775.940987,
+   "value": 31732494964.235413,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1384,7 +1688,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2030,
-   "value": 31732497033.93507,
+   "value": 31732498638.635994,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1393,7 +1699,9 @@
   {
    "metric_id": "receipts.business_rates",
    "year": 2031,
-   "value": 31732498138.642197,
+   "value": 31732494471.035408,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1402,7 +1710,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2025,
-   "value": 19447521756.60174,
+   "value": 19073759714.657246,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1411,7 +1721,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2026,
-   "value": 20439906422.593903,
+   "value": 20077204232.549347,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1420,7 +1732,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2027,
-   "value": 21414316294.15224,
+   "value": 21035871774.44113,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1429,7 +1743,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2028,
-   "value": 22393098228.154316,
+   "value": 21999031263.396732,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1438,7 +1754,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2029,
-   "value": 23394928012.007107,
+   "value": 22985619104.754326,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1447,7 +1765,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2030,
-   "value": 24493314488.64765,
+   "value": 24063362268.549835,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1456,7 +1776,9 @@
   {
    "metric_id": "receipts.sdlt_household",
    "year": 2031,
-   "value": 25645659350.923958,
+   "value": 25218986028.960094,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1465,7 +1787,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2025,
-   "value": 2926955.7028617123,
+   "value": 3441794.3282832364,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1474,7 +1798,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2026,
-   "value": 3159363.4106524643,
+   "value": 3718451.781090757,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1483,7 +1809,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2027,
-   "value": 3426934.00067959,
+   "value": 4036378.263004425,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1492,7 +1820,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2028,
-   "value": 3700930.558409606,
+   "value": 4360394.001039479,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1501,7 +1831,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2029,
-   "value": 3976395.985409789,
+   "value": 4685725.303715903,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1510,7 +1842,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2030,
-   "value": 4283730.381307287,
+   "value": 5044918.447127742,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1519,7 +1853,9 @@
   {
    "metric_id": "receipts.land_transaction_tax",
    "year": 2031,
-   "value": 4617409.568686154,
+   "value": 5422944.119211734,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1528,7 +1864,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2025,
-   "value": 99491389.10783455,
+   "value": 109691161.84922537,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1537,7 +1875,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2026,
-   "value": 103957133.89622791,
+   "value": 114611758.83902286,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1546,7 +1886,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2027,
-   "value": 109071438.72328326,
+   "value": 120242919.16397013,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1555,7 +1897,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2028,
-   "value": 114234820.44540606,
+   "value": 125932263.95004636,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1564,7 +1908,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2029,
-   "value": 119415529.40185314,
+   "value": 131640517.58306551,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1573,7 +1919,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2030,
-   "value": 125108787.1325237,
+   "value": 137912689.4621755,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1582,7 +1930,9 @@
   {
    "metric_id": "receipts.land_and_buildings_transaction_tax",
    "year": 2031,
-   "value": 130998504.05282259,
+   "value": 144400087.45167437,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1592,6 +1942,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1601,6 +1953,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1610,6 +1964,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1619,6 +1975,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1628,6 +1986,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1637,6 +1997,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1646,6 +2008,8 @@
    "metric_id": "receipts.corporate_incident_tax_change",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1655,6 +2019,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1664,6 +2030,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1673,6 +2041,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1682,6 +2052,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1691,6 +2063,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1700,6 +2074,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1709,6 +2085,8 @@
    "metric_id": "receipts.consumer_incident_tax_change",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -1718,6 +2096,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1727,6 +2107,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1736,6 +2118,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1745,6 +2129,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1754,6 +2140,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1763,6 +2151,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1772,6 +2162,8 @@
    "metric_id": "receipts.wealth_tax",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -1781,6 +2173,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1790,6 +2184,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1799,6 +2195,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1808,6 +2206,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1817,6 +2217,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1826,6 +2228,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1835,6 +2239,8 @@
    "metric_id": "receipts.non_primary_residence_wealth_tax",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -1844,6 +2250,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1853,6 +2261,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1862,6 +2272,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1871,6 +2283,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1880,6 +2294,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1889,6 +2305,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1898,6 +2316,8 @@
    "metric_id": "receipts.land_value_tax",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -1907,6 +2327,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1916,6 +2338,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1925,6 +2349,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1934,6 +2360,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1943,6 +2371,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1952,6 +2382,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1961,6 +2393,8 @@
    "metric_id": "receipts.carbon_tax",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -1969,7 +2403,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2025,
-   "value": 123608843187.93976,
+   "value": 122503036176.28136,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -1978,7 +2414,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2026,
-   "value": 128313805027.58318,
+   "value": 127115003712.11774,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -1987,7 +2425,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2027,
-   "value": 130127006024.04692,
+   "value": 128280611587.4219,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -1996,7 +2436,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2028,
-   "value": 132238843074.43095,
+   "value": 130209285651.49004,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2005,7 +2447,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2029,
-   "value": 136141146063.11377,
+   "value": 134051705144.42847,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2014,7 +2458,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2030,
-   "value": 140172899465.68817,
+   "value": 138021583333.92395,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2023,7 +2469,9 @@
   {
    "metric_id": "spending.state_pension",
    "year": 2031,
-   "value": 144295261485.49826,
+   "value": 142080411583.76672,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2032,7 +2480,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2025,
-   "value": 11410127.781640545,
+   "value": 11307942.897278756,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2041,7 +2491,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2026,
-   "value": 11314830.782796293,
+   "value": 11208358.708708271,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2050,7 +2502,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2027,
-   "value": 11062132.340065777,
+   "value": 10906221.550106525,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2059,7 +2513,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2028,
-   "value": 10978110.546501547,
+   "value": 10811938.301638946,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2068,7 +2524,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2029,
-   "value": 11026414.415012136,
+   "value": 10859510.9701875,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2077,7 +2535,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2030,
-   "value": 11076033.608679011,
+   "value": 10908379.084595531,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2086,7 +2546,9 @@
   {
    "metric_id": "caseloads.state_pension",
    "year": 2031,
-   "value": 11123681.665928766,
+   "value": 10955285.089603484,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2095,7 +2557,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2025,
-   "value": 6693405148.200283,
+   "value": 6683600257.719555,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2104,7 +2568,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2026,
-   "value": 7053483709.162087,
+   "value": 7056299099.336407,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2113,7 +2579,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2027,
-   "value": 7033310841.277825,
+   "value": 7040775597.466119,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2122,7 +2590,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2028,
-   "value": 7106016715.233224,
+   "value": 7110102297.589521,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2131,7 +2601,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2029,
-   "value": 7226848094.900362,
+   "value": 7231026514.317166,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2140,7 +2612,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2030,
-   "value": 7357686467.835372,
+   "value": 7365763489.682707,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2149,7 +2623,9 @@
   {
    "metric_id": "spending.pension_credit",
    "year": 2031,
-   "value": 6706505197.30149,
+   "value": 7463303552.117271,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2158,7 +2634,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2025,
-   "value": 1482756.0540938377,
+   "value": 1490774.5672746152,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2167,7 +2645,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2026,
-   "value": 1480853.1148245037,
+   "value": 1489116.733679533,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2176,7 +2656,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2027,
-   "value": 1468135.4329868257,
+   "value": 1477429.6021682024,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2185,7 +2667,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2028,
-   "value": 1447010.371819973,
+   "value": 1455339.335629344,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2194,7 +2678,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2029,
-   "value": 1447749.8420774192,
+   "value": 1457221.2425712496,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2203,7 +2689,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2030,
-   "value": 1444977.4954886883,
+   "value": 1454060.4666527808,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2212,7 +2700,9 @@
   {
    "metric_id": "caseloads.pension_credit",
    "year": 2031,
-   "value": 1071942.0777988583,
+   "value": 1450518.8676682264,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2221,7 +2711,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2025,
-   "value": 1703858030.6710334,
+   "value": 1696782924.1721363,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2230,7 +2722,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2026,
-   "value": 1687685652.7937918,
+   "value": 1679283343.732223,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2239,7 +2733,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2027,
-   "value": 1616450871.1886823,
+   "value": 1590003738.0768867,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2248,7 +2744,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2028,
-   "value": 1595491327.4155288,
+   "value": 1573027080.7015598,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2257,7 +2755,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2029,
-   "value": 1589373766.706106,
+   "value": 1569952442.020166,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2266,7 +2766,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2030,
-   "value": 1572193208.341339,
+   "value": 1547501174.76131,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2275,7 +2777,9 @@
   {
    "metric_id": "spending.winter_fuel_payment",
    "year": 2031,
-   "value": 1561450492.8642156,
+   "value": 1519503572.7274477,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2284,7 +2788,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2025,
-   "value": 7112673.635766387,
+   "value": 7090970.121831879,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2293,7 +2799,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2026,
-   "value": 7034862.558265865,
+   "value": 7007600.1749506295,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2302,7 +2810,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2027,
-   "value": 6701440.449254692,
+   "value": 6593488.894350678,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2311,7 +2821,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2028,
-   "value": 6595675.344529897,
+   "value": 6508639.181520969,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2320,7 +2832,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2029,
-   "value": 6562245.612942323,
+   "value": 6490585.181142107,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2329,7 +2843,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2030,
-   "value": 6475253.517584786,
+   "value": 6377424.451988548,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2338,7 +2854,9 @@
   {
    "metric_id": "caseloads.winter_fuel_payment",
    "year": 2031,
-   "value": 6396321.154249236,
+   "value": 6242475.78672789,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2347,7 +2865,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2025,
-   "value": 195652682.01216725,
+   "value": 190004357.0627768,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2356,7 +2876,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2026,
-   "value": 203249126.6687394,
+   "value": 197376523.34808874,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2365,7 +2887,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2027,
-   "value": 207355049.2189332,
+   "value": 201464846.70418116,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2374,7 +2898,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2028,
-   "value": 211194062.34368283,
+   "value": 205237714.89489964,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2383,7 +2909,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2029,
-   "value": 216365284.1364411,
+   "value": 210263123.1305548,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2392,7 +2920,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2030,
-   "value": 221685784.68137968,
+   "value": 215433546.71501532,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2401,7 +2931,9 @@
   {
    "metric_id": "spending.pawhp",
    "year": 2031,
-   "value": 227092425.0723793,
+   "value": 220687250.38609877,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2410,7 +2942,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2025,
-   "value": 829304.9473122358,
+   "value": 806440.3659721613,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2419,7 +2953,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2026,
-   "value": 829534.2019373178,
+   "value": 806642.316529274,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2428,7 +2964,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2027,
-   "value": 829233.4100881219,
+   "value": 806823.3181906939,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2437,7 +2975,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2028,
-   "value": 827297.3866233826,
+   "value": 805142.1836649776,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2446,7 +2986,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2029,
-   "value": 830937.4991832376,
+   "value": 808684.8276723027,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2455,7 +2997,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2030,
-   "value": 834676.7390937805,
+   "value": 812323.9398192763,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2464,7 +3008,9 @@
   {
    "metric_id": "caseloads.pawhp",
    "year": 2031,
-   "value": 838267.4468256831,
+   "value": 815816.9233164787,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2473,7 +3019,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2025,
-   "value": 79297069929.09415,
+   "value": 79166098634.76385,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2482,7 +3030,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2026,
-   "value": 83589492640.30864,
+   "value": 83483281466.41425,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2491,7 +3041,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2027,
-   "value": 85214410402.33775,
+   "value": 85110190875.9473,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2500,7 +3052,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2028,
-   "value": 86751184502.34996,
+   "value": 86667339883.95622,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2509,7 +3063,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2029,
-   "value": 87589733492.11055,
+   "value": 87402948162.99124,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2518,7 +3074,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2030,
-   "value": 84522628500.50685,
+   "value": 84214027875.53,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2527,7 +3085,9 @@
   {
    "metric_id": "spending.universal_credit",
    "year": 2031,
-   "value": 84959856870.21652,
+   "value": 85457636655.59526,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -2536,7 +3096,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2025,
-   "value": 6348321.546875536,
+   "value": 6371587.519835666,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2545,7 +3107,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2026,
-   "value": 6360591.7880883515,
+   "value": 6379016.747252494,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2554,7 +3118,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2027,
-   "value": 6371549.96376504,
+   "value": 6394538.736335561,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2563,7 +3129,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2028,
-   "value": 6387956.646527201,
+   "value": 6399621.182661429,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2572,7 +3140,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2029,
-   "value": 6368112.714898095,
+   "value": 6373153.488585249,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2581,7 +3151,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2030,
-   "value": 6306509.543026373,
+   "value": 6316123.800888762,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2590,7 +3162,9 @@
   {
    "metric_id": "caseloads.universal_credit",
    "year": 2031,
-   "value": 6290932.269934744,
+   "value": 6311765.528904498,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -2599,7 +3173,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2025,
-   "value": 8156481113.662994,
+   "value": 8595335171.520943,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2608,7 +3184,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2026,
-   "value": 8481531600.187535,
+   "value": 8931864198.577654,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2617,7 +3195,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2027,
-   "value": 8730679159.952463,
+   "value": 9199477872.067867,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2626,7 +3206,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2028,
-   "value": 8864953021.672188,
+   "value": 9343759945.943094,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2635,7 +3217,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2029,
-   "value": 9128777068.594437,
+   "value": 9621753903.580982,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2644,7 +3228,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2030,
-   "value": 9364726526.233978,
+   "value": 9883322170.08307,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2653,7 +3239,9 @@
   {
    "metric_id": "spending.housing_benefit",
    "year": 2031,
-   "value": 7910651616.326078,
+   "value": 10165697938.801252,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -2662,7 +3250,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2025,
-   "value": 1231862.2140089273,
+   "value": 1254488.0164678842,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2671,7 +3261,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2026,
-   "value": 1232121.5733534694,
+   "value": 1252740.275393933,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2680,7 +3272,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2027,
-   "value": 1233595.1880552769,
+   "value": 1254335.1581986696,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2689,7 +3283,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2028,
-   "value": 1219421.9009352624,
+   "value": 1240028.0728783756,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2698,7 +3294,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2029,
-   "value": 1224496.4099243134,
+   "value": 1244626.769205615,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2707,7 +3305,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2030,
-   "value": 1225629.5051008165,
+   "value": 1246801.715999484,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2716,7 +3316,9 @@
   {
    "metric_id": "caseloads.housing_benefit",
    "year": 2031,
-   "value": 1040899.9826000333,
+   "value": 1249258.3732767105,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -2725,7 +3327,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2025,
-   "value": 2113520041.1605535,
+   "value": 1988515658.8280945,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2734,7 +3338,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2026,
-   "value": 2160301971.6342654,
+   "value": 2033885987.1873639,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2743,7 +3349,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2027,
-   "value": 2208773724.380773,
+   "value": 2079220973.3377244,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2752,7 +3360,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2028,
-   "value": 2263288488.6852794,
+   "value": 2130392978.7542346,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2761,7 +3371,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2029,
-   "value": 2318590052.1342373,
+   "value": 2182371431.2323685,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2770,7 +3382,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2030,
-   "value": 2383255853.6602764,
+   "value": 2245332431.4065833,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2779,7 +3393,9 @@
   {
    "metric_id": "spending.council_tax_reduction",
    "year": 2031,
-   "value": 2140059095.905221,
+   "value": 2299546088.50543,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -2788,7 +3404,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2025,
-   "value": 3390071.4158337414,
+   "value": 3187241.3228853345,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2797,7 +3415,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2026,
-   "value": 3414428.1972658634,
+   "value": 3211653.8483200073,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2806,7 +3426,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2027,
-   "value": 3432134.60831666,
+   "value": 3226461.487433046,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2815,7 +3437,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2028,
-   "value": 3454574.494795531,
+   "value": 3249134.5323915184,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2824,7 +3448,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2029,
-   "value": 3471370.6449995935,
+   "value": 3264581.2450436354,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2833,7 +3459,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2030,
-   "value": 3503850.509585738,
+   "value": 3296161.365950793,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2842,7 +3470,9 @@
   {
    "metric_id": "caseloads.council_tax_reduction",
    "year": 2031,
-   "value": 3284019.218611926,
+   "value": 3310563.1543370783,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -2851,7 +3481,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2025,
-   "value": 2157918345.897898,
+   "value": 2119219755.27102,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2860,7 +3492,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2026,
-   "value": 2215460941.2027354,
+   "value": 2175740626.0724893,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2869,7 +3503,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2027,
-   "value": 2267178997.307175,
+   "value": 2226624100.582522,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2878,7 +3514,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2028,
-   "value": 2318791077.751506,
+   "value": 2277324834.952569,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2887,7 +3525,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2029,
-   "value": 2374655132.983756,
+   "value": 2332267574.159017,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2896,7 +3536,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2030,
-   "value": 2432303236.337222,
+   "value": 2388837175.037817,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2905,7 +3547,9 @@
   {
    "metric_id": "spending.esa_income",
    "year": 2031,
-   "value": 2490528072.8603873,
+   "value": 2446074707.6473985,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -2914,7 +3558,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2025,
-   "value": 188801.45329512656,
+   "value": 186830.98939606547,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2923,7 +3569,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2026,
-   "value": 189518.90480037034,
+   "value": 187540.95343746245,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2932,7 +3580,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2027,
-   "value": 190220.12851785123,
+   "value": 188234.8581573367,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2941,7 +3591,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2028,
-   "value": 190792.28100878,
+   "value": 188797.70078976452,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2950,7 +3602,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2029,
-   "value": 191631.7696904242,
+   "value": 189628.41371196508,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2959,7 +3613,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2030,
-   "value": 192494.11825346947,
+   "value": 190481.74765598774,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2968,7 +3624,9 @@
   {
    "metric_id": "caseloads.esa_income",
    "year": 2031,
-   "value": 193322.20888361335,
+   "value": 191300.81845253706,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -2977,7 +3635,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2025,
-   "value": 5185465918.024606,
+   "value": 5221642514.164815,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -2986,7 +3646,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2026,
-   "value": 5324889662.558813,
+   "value": 5362038966.389469,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -2995,7 +3657,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2027,
-   "value": 5451483839.668319,
+   "value": 5489516286.663287,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3004,7 +3668,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2028,
-   "value": 5582755219.611585,
+   "value": 5621703470.566074,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3013,7 +3679,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2029,
-   "value": 5719465848.776321,
+   "value": 5759367828.016521,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3022,7 +3690,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2030,
-   "value": 5860107436.9060955,
+   "value": 5900990569.133743,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3031,7 +3701,9 @@
   {
    "metric_id": "spending.esa_contrib",
    "year": 2031,
-   "value": 6003027242.14748,
+   "value": 6044892357.516051,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3040,7 +3712,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2025,
-   "value": 716681.2252025008,
+   "value": 721684.3135545999,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3049,7 +3723,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2026,
-   "value": 719404.6381566375,
+   "value": 724426.7398380041,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3058,7 +3734,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2027,
-   "value": 722066.4522648603,
+   "value": 727107.1310208887,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3067,7 +3745,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2028,
-   "value": 724954.6817337871,
+   "value": 730015.5208309293,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3076,7 +3756,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2029,
-   "value": 728144.496014744,
+   "value": 733227.5983880013,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3085,7 +3767,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2030,
-   "value": 731421.169972077,
+   "value": 736527.1409217119,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3094,7 +3778,9 @@
   {
    "metric_id": "caseloads.esa_contrib",
    "year": 2031,
-   "value": 734567.6720936149,
+   "value": 739694.2040582746,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3103,7 +3789,9 @@
   {
    "metric_id": "spending.jsa_income",
    "year": 2025,
-   "value": 2091746.573322478,
+   "value": 1446979.5182146362,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3113,6 +3801,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3122,6 +3812,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3131,6 +3823,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3140,6 +3834,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3149,6 +3845,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3158,6 +3856,8 @@
    "metric_id": "spending.jsa_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3166,7 +3866,9 @@
   {
    "metric_id": "caseloads.jsa_income",
    "year": 2025,
-   "value": 428.6262260079384,
+   "value": 278.16873490810394,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3176,6 +3878,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3185,6 +3889,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3194,6 +3900,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3203,6 +3911,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3212,6 +3922,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3221,6 +3933,8 @@
    "metric_id": "caseloads.jsa_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3229,7 +3943,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2025,
-   "value": 297414211.9393128,
+   "value": 288777970.5356167,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3238,7 +3954,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2026,
-   "value": 305410902.6767736,
+   "value": 296542457.71586204,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3247,7 +3965,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2027,
-   "value": 312671758.9873353,
+   "value": 303592471.1494838,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3256,7 +3976,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2028,
-   "value": 320200875.2165054,
+   "value": 310902955.13914746,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3265,7 +3987,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2029,
-   "value": 328041963.6404445,
+   "value": 318516348.7643643,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3274,7 +3998,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2030,
-   "value": 336108514.2782755,
+   "value": 326348673.79918647,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3283,7 +4009,9 @@
   {
    "metric_id": "spending.jsa_contrib",
    "year": 2031,
-   "value": 344305739.25844115,
+   "value": 334307010.21562654,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3292,7 +4020,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2025,
-   "value": 69247.07556176186,
+   "value": 67182.8121483326,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3301,7 +4031,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2026,
-   "value": 69510.21602272987,
+   "value": 67438.10866451263,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3310,7 +4042,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2027,
-   "value": 69767.40603733063,
+   "value": 67687.63075757027,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3319,7 +4053,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2028,
-   "value": 70046.47099995613,
+   "value": 67958.37626743317,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3328,7 +4064,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2029,
-   "value": 70354.67849779129,
+   "value": 68257.39367341995,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3337,7 +4075,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2030,
-   "value": 70671.27628540993,
+   "value": 68564.55532884598,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3346,7 +4086,9 @@
   {
    "metric_id": "caseloads.jsa_contrib",
    "year": 2031,
-   "value": 70975.29594826698,
+   "value": 68859.38249921799,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -3355,7 +4097,9 @@
   {
    "metric_id": "spending.income_support",
    "year": 2025,
-   "value": 168861494.13127527,
+   "value": 123955194.70721354,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3365,6 +4109,8 @@
    "metric_id": "spending.income_support",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3374,6 +4120,8 @@
    "metric_id": "spending.income_support",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3383,6 +4131,8 @@
    "metric_id": "spending.income_support",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3392,6 +4142,8 @@
    "metric_id": "spending.income_support",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3401,6 +4153,8 @@
    "metric_id": "spending.income_support",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3410,6 +4164,8 @@
    "metric_id": "spending.income_support",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -3418,7 +4174,9 @@
   {
    "metric_id": "caseloads.income_support",
    "year": 2025,
-   "value": 34027.1418364048,
+   "value": 24803.04834920168,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3428,6 +4186,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3437,6 +4197,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3446,6 +4208,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3455,6 +4219,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3464,6 +4230,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3473,6 +4241,8 @@
    "metric_id": "caseloads.income_support",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -3482,6 +4252,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3491,6 +4263,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3500,6 +4274,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3509,6 +4285,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3518,6 +4296,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3527,6 +4307,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3536,6 +4318,8 @@
    "metric_id": "spending.working_tax_credit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -3545,6 +4329,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3554,6 +4340,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3563,6 +4351,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3572,6 +4362,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3581,6 +4373,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3590,6 +4384,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3599,6 +4395,8 @@
    "metric_id": "caseloads.working_tax_credit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -3608,6 +4406,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3617,6 +4417,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3626,6 +4428,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3635,6 +4439,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3644,6 +4450,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3653,6 +4461,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3662,6 +4472,8 @@
    "metric_id": "spending.child_tax_credit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -3671,6 +4483,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3680,6 +4494,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3689,6 +4505,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3698,6 +4516,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3707,6 +4527,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3716,6 +4538,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3725,6 +4549,8 @@
    "metric_id": "caseloads.child_tax_credit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -3734,6 +4560,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3743,6 +4571,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3752,6 +4582,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3761,6 +4593,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3770,6 +4604,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3779,6 +4615,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3788,6 +4626,8 @@
    "metric_id": "spending.incapacity_benefit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -3797,6 +4637,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3806,6 +4648,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3815,6 +4659,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3824,6 +4670,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3833,6 +4681,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3842,6 +4692,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3851,6 +4703,8 @@
    "metric_id": "caseloads.incapacity_benefit",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -3859,7 +4713,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2025,
-   "value": 26930742886.35225,
+   "value": 27050796518.958164,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3868,7 +4724,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2026,
-   "value": 28062341229.807953,
+   "value": 28187504820.35819,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3877,7 +4735,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2027,
-   "value": 28813932611.682465,
+   "value": 28942448438.6212,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3886,7 +4746,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2028,
-   "value": 29507723865.475834,
+   "value": 29639334288.533737,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3895,7 +4757,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2029,
-   "value": 30230279635.690178,
+   "value": 30365112782.59276,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3904,7 +4768,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2030,
-   "value": 30973577012.717224,
+   "value": 31111725337.197277,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3913,7 +4779,9 @@
   {
    "metric_id": "spending.pip",
    "year": 2031,
-   "value": 31728969558.821815,
+   "value": 31870426624.368805,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -3922,7 +4790,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2025,
-   "value": 3561191.43436794,
+   "value": 3581346.50325121,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3931,7 +4801,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2026,
-   "value": 3574724.089687288,
+   "value": 3594955.7513322085,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3940,7 +4812,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2027,
-   "value": 3587950.6320851147,
+   "value": 3608257.1502955705,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3949,7 +4823,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2028,
-   "value": 3602302.242634833,
+   "value": 3622690.0020009577,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3958,7 +4834,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2029,
-   "value": 3618152.4307922274,
+   "value": 3638629.8922510594,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3967,7 +4845,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2030,
-   "value": 3634434.2309794426,
+   "value": 3655003.834502399,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3976,7 +4856,9 @@
   {
    "metric_id": "caseloads.pip",
    "year": 2031,
-   "value": 3650069.225597918,
+   "value": 3670720.34740828,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -3985,7 +4867,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2025,
-   "value": 7484533549.186283,
+   "value": 7519515429.343498,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -3994,7 +4878,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2026,
-   "value": 7798317749.580545,
+   "value": 7834750092.336622,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4003,7 +4889,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2027,
-   "value": 8007179295.781675,
+   "value": 8044587394.8355665,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4012,7 +4900,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2028,
-   "value": 8199978749.538992,
+   "value": 8238287553.0089445,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4021,7 +4911,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2029,
-   "value": 8400772001.314109,
+   "value": 8440018870.958048,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4030,7 +4922,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2030,
-   "value": 8607328838.619286,
+   "value": 8647540725.08345,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4039,7 +4933,9 @@
   {
    "metric_id": "spending.dla",
    "year": 2031,
-   "value": 8817246875.370478,
+   "value": 8858422643.224787,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4048,7 +4944,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2025,
-   "value": 1334888.5791397095,
+   "value": 1296293.76486139,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4057,7 +4955,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2026,
-   "value": 1339961.2010401338,
+   "value": 1301219.7249682397,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4066,7 +4966,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2027,
-   "value": 1344919.083814323,
+   "value": 1306034.2623415291,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4075,7 +4977,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2028,
-   "value": 1350298.687692389,
+   "value": 1311258.3262985945,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4084,7 +4988,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2029,
-   "value": 1356240.0184779614,
+   "value": 1317027.8841654807,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4093,7 +4999,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2030,
-   "value": 1362343.138695091,
+   "value": 1322954.550306335,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4102,7 +5010,9 @@
   {
    "metric_id": "caseloads.dla",
    "year": 2031,
-   "value": 1368203.8070302308,
+   "value": 1328643.2488841116,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4111,7 +5021,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2025,
-   "value": 8738849002.944973,
+   "value": 8713069613.537264,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4120,7 +5032,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2026,
-   "value": 9105426589.661386,
+   "value": 9078584120.844625,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4129,7 +5043,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2027,
-   "value": 9349296216.992481,
+   "value": 9321734807.6616,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4138,7 +5054,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2028,
-   "value": 9574411518.877106,
+   "value": 9546186520.166021,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4147,7 +5065,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2029,
-   "value": 9808860827.118614,
+   "value": 9779944679.35845,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4156,7 +5076,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2030,
-   "value": 10050039243.53858,
+   "value": 10020412141.96302,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4165,7 +5087,9 @@
   {
    "metric_id": "spending.attendance_allowance",
    "year": 2031,
-   "value": 10295142509.771086,
+   "value": 10264773293.632841,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -4174,7 +5098,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2025,
-   "value": 1716598.859297052,
+   "value": 1701405.523672521,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4183,7 +5109,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2026,
-   "value": 1723121.9867911339,
+   "value": 1707870.9254432172,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4192,7 +5120,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2027,
-   "value": 1729497.5712008923,
+   "value": 1714190.0767204762,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4201,7 +5131,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2028,
-   "value": 1736415.4675818533,
+   "value": 1721046.7521996498,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4210,7 +5142,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2029,
-   "value": 1744055.7271453738,
+   "value": 1728619.3880579919,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4219,7 +5153,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2030,
-   "value": 1751904.025848925,
+   "value": 1736398.2265275419,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4228,7 +5164,9 @@
   {
    "metric_id": "caseloads.attendance_allowance",
    "year": 2031,
-   "value": 1759440.5596084595,
+   "value": 1743864.7361019552,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -4237,7 +5175,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2025,
-   "value": 4648737205.678978,
+   "value": 4498304384.942733,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4246,7 +5186,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2026,
-   "value": 4842862964.368323,
+   "value": 4686148233.621847,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4255,7 +5197,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2027,
-   "value": 4972568907.329457,
+   "value": 4811656899.117326,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4264,7 +5208,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2028,
-   "value": 5092300033.036156,
+   "value": 4927513579.343729,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4273,7 +5219,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2029,
-   "value": 5216995990.439329,
+   "value": 5048174373.178411,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4282,7 +5230,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2030,
-   "value": 5345270444.763329,
+   "value": 5168683430.088493,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4291,7 +5241,9 @@
   {
    "metric_id": "spending.carers_allowance",
    "year": 2031,
-   "value": 5475632307.34242,
+   "value": 5294728594.298446,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -4300,7 +5252,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2025,
-   "value": 1073214.7707251012,
+   "value": 1038485.6135211289,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4309,7 +5263,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2026,
-   "value": 1077293.0261095166,
+   "value": 1042431.8938074112,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4318,7 +5274,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2027,
-   "value": 1081279.032247901,
+   "value": 1046288.9127022028,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4327,7 +5285,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2028,
-   "value": 1085604.089460224,
+   "value": 1050474.0211501122,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4336,7 +5296,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2029,
-   "value": 1090380.7663949132,
+   "value": 1055096.1227512658,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4345,7 +5307,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2030,
-   "value": 1095287.5083169043,
+   "value": 1059103.4548994005,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4354,7 +5318,9 @@
   {
    "metric_id": "caseloads.carers_allowance",
    "year": 2031,
-   "value": 1099999.3295924067,
+   "value": 1063657.5973686576,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -4363,7 +5329,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2025,
-   "value": 375132605.30346316,
+   "value": 352284662.9714799,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4372,7 +5340,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2026,
-   "value": 390797693.02699834,
+   "value": 366995656.0579343,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4381,7 +5351,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2027,
-   "value": 401264392.71339667,
+   "value": 376824870.322693,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4390,7 +5362,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2028,
-   "value": 410926172.48663545,
+   "value": 385898182.16357577,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4399,7 +5373,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2029,
-   "value": 420988584.3188077,
+   "value": 395347728.7181926,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4408,7 +5384,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2030,
-   "value": 431339766.7553348,
+   "value": 405068460.50986433,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4417,7 +5395,9 @@
   {
    "metric_id": "spending.carer_support_payment",
    "year": 2031,
-   "value": 441859394.4117867,
+   "value": 414946587.8089589,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -4426,7 +5406,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2025,
-   "value": 86603.70229154825,
+   "value": 81328.99044907093,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4435,7 +5417,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2026,
-   "value": 86932.79830861092,
+   "value": 81638.04422974586,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4444,7 +5428,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2027,
-   "value": 87254.451836586,
+   "value": 81940.10755866766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4453,7 +5439,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2028,
-   "value": 87603.46610051394,
+   "value": 82267.86362826824,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4462,7 +5450,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2029,
-   "value": 87988.92237108946,
+   "value": 82629.84296369553,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4471,7 +5461,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2030,
-   "value": 88384.87467557192,
+   "value": 83001.67959588766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4480,7 +5472,9 @@
   {
    "metric_id": "caseloads.carer_support_payment",
    "year": 2031,
-   "value": 88765.09786373377,
+   "value": 83358.58633065224,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -4490,6 +5484,8 @@
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4498,7 +5494,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2026,
-   "value": 52889916.61334165,
+   "value": 49668588.102493696,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4507,7 +5505,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2027,
-   "value": 53085610.62761456,
+   "value": 49852363.43918431,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4516,7 +5516,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2028,
-   "value": 53297950.914309174,
+   "value": 50051770.239931166,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4525,7 +5527,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2029,
-   "value": 53532462.518737875,
+   "value": 50271998.47644251,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4534,7 +5538,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2030,
-   "value": 53773359.910451815,
+   "value": 50498223.892546244,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4543,7 +5549,9 @@
   {
    "metric_id": "spending.scottish_carer_supplement",
    "year": 2031,
-   "value": 54004687.70741227,
+   "value": 50715365.95869056,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -4553,6 +5561,8 @@
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4561,7 +5571,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2026,
-   "value": 86932.79830861092,
+   "value": 81638.04422974586,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4570,7 +5582,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2027,
-   "value": 87254.451836586,
+   "value": 81940.10755866766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4579,7 +5593,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2028,
-   "value": 87603.46610051394,
+   "value": 82267.86362826824,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4588,7 +5604,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2029,
-   "value": 87988.92237108946,
+   "value": 82629.84296369553,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4597,7 +5615,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2030,
-   "value": 88384.87467557192,
+   "value": 83001.67959588766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4606,7 +5626,9 @@
   {
    "metric_id": "caseloads.scottish_carer_supplement",
    "year": 2031,
-   "value": 88765.09786373377,
+   "value": 83358.58633065224,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -4615,7 +5637,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2025,
-   "value": 22916850.46898842,
+   "value": 26001911.186065674,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4624,7 +5648,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2026,
-   "value": 23874085.23946771,
+   "value": 27088007.985394344,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4633,7 +5659,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2027,
-   "value": 24513501.268621735,
+   "value": 27813501.58527428,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4642,7 +5670,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2028,
-   "value": 25103746.46338744,
+   "value": 28483206.305987563,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4651,7 +5681,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2029,
-   "value": 25718463.554498497,
+   "value": 29180676.754239403,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4660,7 +5692,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2030,
-   "value": 26350824.69866039,
+   "value": 29898167.047436927,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4669,7 +5703,9 @@
   {
    "metric_id": "spending.sda",
    "year": 2031,
-   "value": 26993475.082385655,
+   "value": 30627272.264840692,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -4678,7 +5714,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2025,
-   "value": 3832.2492423057556,
+   "value": 4348.145683288574,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4687,7 +5725,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2026,
-   "value": 3846.8119764328003,
+   "value": 4364.668739795685,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4696,7 +5736,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2027,
-   "value": 3861.0452857017517,
+   "value": 4380.818064212799,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4705,7 +5747,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2028,
-   "value": 3876.4891839027405,
+   "value": 4398.341153144836,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4714,7 +5758,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2029,
-   "value": 3893.5458583831787,
+   "value": 4417.694038391113,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4723,7 +5769,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2030,
-   "value": 3911.066900253296,
+   "value": 4437.573884487152,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4732,7 +5780,9 @@
   {
    "metric_id": "caseloads.sda",
    "year": 2031,
-   "value": 3927.8920154571533,
+   "value": 4456.655462741852,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -4741,7 +5791,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2025,
-   "value": 507122677.50677097,
+   "value": 505396316.7142715,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4750,7 +5802,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2026,
-   "value": 520757913.07925874,
+   "value": 518985130.7359581,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4759,7 +5813,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2027,
-   "value": 533138408.2492215,
+   "value": 531323482.42515385,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4768,7 +5824,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2028,
-   "value": 545976365.926789,
+   "value": 544117734.2383146,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4777,7 +5835,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2029,
-   "value": 559346215.9575605,
+   "value": 557442066.9128101,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4786,7 +5846,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2030,
-   "value": 573100581.8244832,
+   "value": 571149605.5284191,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4795,7 +5857,9 @@
   {
    "metric_id": "spending.iidb",
    "year": 2031,
-   "value": 587077716.6684005,
+   "value": 585077668.0455391,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -4804,7 +5868,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2025,
-   "value": 136309.47050744295,
+   "value": 137473.5583550036,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4813,7 +5879,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2026,
-   "value": 136827.45147165656,
+   "value": 137995.96156597137,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4822,7 +5890,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2027,
-   "value": 137333.71539336443,
+   "value": 138506.54905071855,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4831,7 +5901,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2028,
-   "value": 137883.04356488585,
+   "value": 139060.56764179468,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4840,7 +5912,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2029,
-   "value": 138489.7313208878,
+   "value": 139672.4357754588,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4849,7 +5923,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2030,
-   "value": 139112.9398522377,
+   "value": 140300.96557214856,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4858,7 +5934,9 @@
   {
    "metric_id": "caseloads.iidb",
    "year": 2031,
-   "value": 139711.38968542218,
+   "value": 140904.25975701213,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -4867,7 +5945,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2025,
-   "value": 568151093.7335573,
+   "value": 608337715.55495,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4876,7 +5956,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2026,
-   "value": 583427211.5685618,
+   "value": 624694356.9666108,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4885,7 +5967,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2027,
-   "value": 597297627.7972465,
+   "value": 639545878.8404102,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4894,7 +5978,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2028,
-   "value": 611680516.7185693,
+   "value": 654946115.3175836,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4903,7 +5989,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2029,
-   "value": 626659337.1968452,
+   "value": 670984438.3106201,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4912,7 +6000,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2030,
-   "value": 642068929.7703295,
+   "value": 687483985.4915761,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4921,7 +6011,9 @@
   {
    "metric_id": "spending.afcs",
    "year": 2031,
-   "value": 657728126.7655065,
+   "value": 704248973.1763016,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -4930,7 +6022,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2025,
-   "value": 87231.42297008634,
+   "value": 93556.20288914442,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4939,7 +6033,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2026,
-   "value": 87562.9048769474,
+   "value": 93911.72057116032,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4948,7 +6044,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2027,
-   "value": 87886.88816124201,
+   "value": 94259.19729825854,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4957,7 +6055,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2028,
-   "value": 88238.43054047227,
+   "value": 94636.23070755601,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4966,7 +6066,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2029,
-   "value": 88626.6806499958,
+   "value": 95052.63239446282,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4975,7 +6077,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2030,
-   "value": 89025.50376203656,
+   "value": 95480.37335321307,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4984,7 +6088,9 @@
   {
    "metric_id": "caseloads.afcs",
    "year": 2031,
-   "value": 89408.48312401772,
+   "value": 95890.9378361702,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -4993,7 +6099,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2025,
-   "value": 16225320972.639776,
+   "value": 16193470845.603186,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5002,7 +6110,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2026,
-   "value": 16896152580.691387,
+   "value": 16865082606.210407,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5011,7 +6121,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2027,
-   "value": 17341380924.037914,
+   "value": 17309224587.32687,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5020,7 +6132,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2028,
-   "value": 17755008028.657654,
+   "value": 17722732649.511974,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5029,7 +6143,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2029,
-   "value": 18184587501.076538,
+   "value": 18149355497.8589,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5038,7 +6154,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2030,
-   "value": 18623367766.380272,
+   "value": 18589683648.812527,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5047,7 +6165,9 @@
   {
    "metric_id": "spending.child_benefit",
    "year": 2031,
-   "value": 19051556819.483387,
+   "value": 19019347515.30189,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -5056,7 +6176,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2025,
-   "value": 8144503.8247400075,
+   "value": 8124933.04077065,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5065,7 +6187,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2026,
-   "value": 8170465.289068207,
+   "value": 8151661.30214186,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5074,7 +6198,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2027,
-   "value": 8197312.676083803,
+   "value": 8178496.28433007,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5083,7 +6209,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2028,
-   "value": 8228525.797302961,
+   "value": 8209901.52580525,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5092,7 +6220,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2029,
-   "value": 8262403.058013514,
+   "value": 8242994.678169802,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5101,7 +6231,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2030,
-   "value": 8295971.741483018,
+   "value": 8277445.224295765,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5110,7 +6242,9 @@
   {
    "metric_id": "caseloads.child_benefit",
    "year": 2031,
-   "value": 8318393.685991436,
+   "value": 8301138.966311127,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -5119,7 +6253,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2025,
-   "value": 497726869.8419192,
+   "value": 496826543.81597674,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5128,7 +6264,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2026,
-   "value": 519612809.90459955,
+   "value": 518442587.758203,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5137,7 +6275,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2027,
-   "value": 533556568.34392536,
+   "value": 532354940.6639104,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5146,7 +6286,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2028,
-   "value": 546831672.8782737,
+   "value": 545600150.271133,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5155,7 +6297,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2029,
-   "value": 557690457.6552503,
+   "value": 557257209.815226,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5164,7 +6308,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2030,
-   "value": 571385467.1006676,
+   "value": 570941579.8039502,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5173,7 +6319,9 @@
   {
    "metric_id": "spending.scottish_child_payment",
    "year": 2031,
-   "value": 579782864.4065932,
+   "value": 579837131.7746521,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -5182,7 +6330,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2025,
-   "value": 352547.7069185972,
+   "value": 351909.9919484854,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5191,7 +6341,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2026,
-   "value": 354345.8819241524,
+   "value": 353547.8581060171,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5200,7 +6352,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2027,
-   "value": 355656.9695440531,
+   "value": 354855.99119508266,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5209,7 +6363,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2028,
-   "value": 357079.5769625902,
+   "value": 356275.3960905075,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5218,7 +6374,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2029,
-   "value": 356899.05693626404,
+   "value": 356621.7960590124,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5227,7 +6385,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2030,
-   "value": 358505.11331129074,
+   "value": 358226.60453784466,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5236,7 +6396,9 @@
   {
    "metric_id": "caseloads.scottish_child_payment",
    "year": 2031,
-   "value": 356640.845736742,
+   "value": 356674.22713041306,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -5246,6 +6408,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5255,6 +6419,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5264,6 +6430,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5273,6 +6441,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5282,6 +6452,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5291,6 +6463,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5300,6 +6474,8 @@
    "metric_id": "spending.two_child_limit_payment",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -5309,6 +6485,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5318,6 +6496,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5327,6 +6507,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5336,6 +6518,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5345,6 +6529,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5354,6 +6540,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5363,6 +6551,8 @@
    "metric_id": "caseloads.two_child_limit_payment",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -5371,7 +6561,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2025,
-   "value": 53970826.290031455,
+   "value": 52030589.486631,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5380,7 +6572,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2026,
-   "value": 54175917.177720994,
+   "value": 52228307.60199582,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5389,7 +6583,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2027,
-   "value": 54376369.043138646,
+   "value": 52421553.321768366,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5398,7 +6594,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2028,
-   "value": 54593871.5011113,
+   "value": 52631236.984368056,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5407,7 +6605,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2029,
-   "value": 54834085.12924674,
+   "value": 52862815.027035154,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5416,7 +6616,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2030,
-   "value": 55080840.175692044,
+   "value": 53100698.99261543,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5425,7 +6627,9 @@
   {
    "metric_id": "spending.healthy_start_vouchers",
    "year": 2031,
-   "value": 55317793.086847685,
+   "value": 53329031.82253713,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -5434,7 +6638,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2025,
-   "value": 208602.1595891416,
+   "value": 200297.54610317945,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5443,7 +6649,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2026,
-   "value": 209394.85441070795,
+   "value": 201058.68415096402,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5452,7 +6660,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2027,
-   "value": 210169.61887291074,
+   "value": 201802.60497659445,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5461,7 +6671,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2028,
-   "value": 211010.2855282426,
+   "value": 202609.80542340875,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5470,7 +6682,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2029,
-   "value": 211938.73312041163,
+   "value": 203501.29058858752,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5479,7 +6693,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2030,
-   "value": 212892.46397477388,
+   "value": 204417.0512445569,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5488,7 +6704,9 @@
   {
    "metric_id": "caseloads.healthy_start_vouchers",
    "year": 2031,
-   "value": 213808.30855458975,
+   "value": 205296.04370743036,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -5498,6 +6716,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5507,6 +6727,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5516,6 +6738,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5525,6 +6749,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5534,6 +6760,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5543,6 +6771,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5552,6 +6782,8 @@
    "metric_id": "spending.maternity_allowance",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -5561,6 +6793,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5570,6 +6804,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5579,6 +6815,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5588,6 +6826,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5597,6 +6837,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5606,6 +6848,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5615,6 +6859,8 @@
    "metric_id": "caseloads.maternity_allowance",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -5623,7 +6869,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2025,
-   "value": 3337974284.302048,
+   "value": 3318182317.450847,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5632,7 +6880,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2026,
-   "value": 3427723791.796866,
+   "value": 3407399609.1208797,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5641,7 +6891,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2027,
-   "value": 3509214573.900618,
+   "value": 3488407179.3860164,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5650,7 +6902,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2028,
-   "value": 3593716240.856939,
+   "value": 3572407800.478435,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5659,7 +6913,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2029,
-   "value": 3681719191.086521,
+   "value": 3659888978.871894,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5668,7 +6924,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2030,
-   "value": 3772252863.671072,
+   "value": 3749885904.2724175,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5677,7 +6935,9 @@
   {
    "metric_id": "spending.statutory_maternity_pay",
    "year": 2031,
-   "value": 3864252917.3662605,
+   "value": 3841330547.982543,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -5686,7 +6946,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2025,
-   "value": 321312.8473469913,
+   "value": 333845.906548053,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5695,7 +6957,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2026,
-   "value": 322533.84839725494,
+   "value": 335114.53039878607,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5704,7 +6968,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2027,
-   "value": 323727.22941863537,
+   "value": 336354.45804458857,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5713,7 +6979,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2028,
-   "value": 325022.1207540333,
+   "value": 337699.85739299655,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5722,7 +6990,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2029,
-   "value": 326452.22118473053,
+   "value": 339185.7411582172,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5731,7 +7001,9 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2030,
-   "value": 327921.2663208842,
+   "value": 340712.0907050073,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -5740,16 +7012,174 @@
   {
    "metric_id": "caseloads.statutory_maternity_pay",
    "year": 2031,
-   "value": 329331.95074787736,
+   "value": 342177.1517958939,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
    "label": "Statutory Maternity Pay"
   },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2025,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2026,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2027,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2028,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2029,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2030,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "spending.statutory_paternity_pay",
+   "year": 2031,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "gbp",
+   "kind": "spending",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2025,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2026,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2027,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2028,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2029,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2030,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
+  {
+   "metric_id": "caseloads.statutory_paternity_pay",
+   "year": 2031,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
+   "unit": "count",
+   "kind": "caseload",
+   "partition": "statutory_paternity_pay",
+   "label": "Statutory Paternity Pay"
+  },
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2025,
-   "value": 1179772370.051021,
+   "value": 1129666049.2058818,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5758,7 +7188,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2026,
-   "value": 1211493383.3111763,
+   "value": 1160039811.2081735,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5767,7 +7199,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2027,
-   "value": 1240295431.5737867,
+   "value": 1187618628.8419445,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5776,7 +7210,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2028,
-   "value": 1270161726.4028587,
+   "value": 1216216439.2552707,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5785,7 +7221,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2029,
-   "value": 1301265465.0001216,
+   "value": 1245999166.4642668,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5794,7 +7232,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2030,
-   "value": 1333263686.1531434,
+   "value": 1276638374.6988342,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5803,7 +7243,9 @@
   {
    "metric_id": "spending.statutory_sick_pay",
    "year": 2031,
-   "value": 1365780194.8969457,
+   "value": 1307770469.3172994,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -5812,7 +7254,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2025,
-   "value": 185810.46695950627,
+   "value": 181849.49628841877,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5821,7 +7265,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2026,
-   "value": 186516.55576607585,
+   "value": 182540.52988168597,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5830,7 +7276,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2027,
-   "value": 187206.66695040464,
+   "value": 183215.93420261145,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5839,7 +7287,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2028,
-   "value": 187955.48840495944,
+   "value": 183948.78862804174,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5848,7 +7298,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2029,
-   "value": 188782.49710434675,
+   "value": 184758.16779726744,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5857,7 +7309,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2030,
-   "value": 189632.02460759878,
+   "value": 185589.58406233788,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5866,7 +7320,9 @@
   {
    "metric_id": "caseloads.statutory_sick_pay",
    "year": 2031,
-   "value": 190447.80656796694,
+   "value": 186387.61916735768,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -5875,7 +7331,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2025,
-   "value": 14081577.514007688,
+   "value": 13125578.55695486,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5884,7 +7342,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2026,
-   "value": 14135088.059857488,
+   "value": 13175456.283032894,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5893,7 +7353,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2027,
-   "value": 14187388.068765402,
+   "value": 13224205.684065819,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5902,7 +7364,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2028,
-   "value": 14244136.843547225,
+   "value": 13277101.755604148,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5911,7 +7375,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2029,
-   "value": 14306811.286181211,
+   "value": 13335521.275147796,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5920,7 +7386,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2030,
-   "value": 14371192.14501977,
+   "value": 13395531.273916364,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5929,7 +7397,9 @@
   {
    "metric_id": "spending.ssmg",
    "year": 2031,
-   "value": 14433015.649303794,
+   "value": 13453131.819739938,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -5938,7 +7408,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2025,
-   "value": 28163.155028015375,
+   "value": 26251.15711390972,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5947,7 +7419,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2026,
-   "value": 28270.176119714975,
+   "value": 26350.91256606579,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5956,7 +7430,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2027,
-   "value": 28374.776137530804,
+   "value": 26448.411368131638,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5965,7 +7441,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2028,
-   "value": 28488.27368709445,
+   "value": 26554.203511208296,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5974,7 +7452,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2029,
-   "value": 28613.622572362423,
+   "value": 26671.04255029559,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5983,7 +7463,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2030,
-   "value": 28742.38429003954,
+   "value": 26791.062547832727,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -5992,7 +7474,9 @@
   {
    "metric_id": "caseloads.ssmg",
    "year": 2031,
-   "value": 28866.031298607588,
+   "value": 26906.263639479876,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -6001,7 +7485,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2025,
-   "value": 654447661.0694321,
+   "value": 670117436.1645457,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6010,7 +7496,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2026,
-   "value": 672044090.7987709,
+   "value": 688135183.9490275,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6019,7 +7507,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2027,
-   "value": 688021282.8463899,
+   "value": 704494923.9662163,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6028,7 +7518,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2028,
-   "value": 704588777.7902418,
+   "value": 721459099.2289677,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6037,7 +7529,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2029,
-   "value": 721842764.085712,
+   "value": 739126209.3696653,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6046,7 +7540,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2030,
-   "value": 739592896.5915165,
+   "value": 757301345.0579464,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6055,7 +7551,9 @@
   {
    "metric_id": "spending.bsp",
    "year": 2031,
-   "value": 757630569.6200083,
+   "value": 775768909.9039654,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -6064,7 +7562,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2025,
-   "value": 92227.57971167564,
+   "value": 98107.17104572058,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6073,7 +7573,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2026,
-   "value": 92578.04749596119,
+   "value": 98479.98137193918,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6082,7 +7584,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2027,
-   "value": 92920.58816957474,
+   "value": 98844.35904490948,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6091,7 +7595,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2028,
-   "value": 93292.26550346613,
+   "value": 99239.73120433092,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6100,7 +7606,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2029,
-   "value": 93702.75265604258,
+   "value": 99676.38774478436,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6109,7 +7617,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2030,
-   "value": 94124.41794991493,
+   "value": 100124.9348872304,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6118,7 +7628,9 @@
   {
    "metric_id": "caseloads.bsp",
    "year": 2031,
-   "value": 94529.3324996233,
+   "value": 100555.47150915861,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -6127,7 +7639,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2025,
-   "value": 563525940.8773441,
+   "value": 551460799.5583543,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6136,7 +7650,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2026,
-   "value": 568299173.1681643,
+   "value": 556759454.765603,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6145,7 +7661,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2027,
-   "value": 573445937.53699,
+   "value": 566094705.6608063,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6154,7 +7672,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2028,
-   "value": 585862809.08509,
+   "value": 577814275.3520343,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6163,7 +7683,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2029,
-   "value": 561084451.3935778,
+   "value": 546986429.725085,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6172,7 +7694,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2030,
-   "value": 580251499.0481504,
+   "value": 566235601.269679,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6181,7 +7705,9 @@
   {
    "metric_id": "spending.tax_free_childcare",
    "year": 2031,
-   "value": 560322627.8579925,
+   "value": 577475011.8886111,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -6190,7 +7716,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2025,
-   "value": 974133.2423208505,
+   "value": 1011592.7329891622,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6199,7 +7727,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2026,
-   "value": 979682.5571617931,
+   "value": 1021183.6429007053,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6208,7 +7738,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2027,
-   "value": 971293.5103004575,
+   "value": 1020334.1701015085,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6217,7 +7749,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2028,
-   "value": 976896.6010332257,
+   "value": 1023999.8023810685,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6226,7 +7760,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2029,
-   "value": 957558.250394702,
+   "value": 972793.2253160179,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6235,7 +7771,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2030,
-   "value": 966774.040873915,
+   "value": 980748.0028229207,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6244,7 +7782,9 @@
   {
    "metric_id": "caseloads.tax_free_childcare",
    "year": 2031,
-   "value": 914534.0746401399,
+   "value": 980979.6002974808,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -6253,7 +7793,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2025,
-   "value": 4769443952.411871,
+   "value": 2648748217.184513,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6262,7 +7804,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2026,
-   "value": 5307606110.253133,
+   "value": 3074999356.8385277,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6271,7 +7815,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2027,
-   "value": 5433878200.598173,
+   "value": 3151701029.7253556,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6280,7 +7826,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2028,
-   "value": 5575606222.716693,
+   "value": 3235525477.42588,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6289,7 +7837,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2029,
-   "value": 5682980459.519588,
+   "value": 3310370308.099014,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6298,7 +7848,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2030,
-   "value": 5856928114.420198,
+   "value": 3398248782.2036104,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6307,7 +7859,9 @@
   {
    "metric_id": "spending.extended_childcare_entitlement",
    "year": 2031,
-   "value": 5926506204.517755,
+   "value": 3482394959.2131405,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -6316,7 +7870,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2025,
-   "value": 962176.1845641136,
+   "value": 664320.1943173409,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6325,7 +7881,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2026,
-   "value": 957668.9594607353,
+   "value": 669802.4551296234,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6334,7 +7892,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2027,
-   "value": 959484.9431653023,
+   "value": 672223.7327985764,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6343,7 +7903,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2028,
-   "value": 963973.5987744331,
+   "value": 673895.0757799149,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6352,7 +7914,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2029,
-   "value": 955768.6225590706,
+   "value": 676376.3725852966,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6361,7 +7925,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2030,
-   "value": 963198.3530750275,
+   "value": 681117.3323864937,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6370,7 +7936,9 @@
   {
    "metric_id": "caseloads.extended_childcare_entitlement",
    "year": 2031,
-   "value": 953890.9335918427,
+   "value": 683408.1116919518,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -6379,7 +7947,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2025,
-   "value": 1303677004.8374069,
+   "value": 3266472521.328236,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6388,7 +7958,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2026,
-   "value": 1372546985.2564154,
+   "value": 3388720332.016673,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6397,7 +7969,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2027,
-   "value": 1412467299.31001,
+   "value": 3479027407.998313,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6406,7 +7980,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2028,
-   "value": 1447975936.2291465,
+   "value": 3565630277.573733,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6415,7 +7991,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2029,
-   "value": 1528607528.5243466,
+   "value": 3653067234.422063,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6424,7 +8002,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2030,
-   "value": 1568458954.5961401,
+   "value": 3757717185.8182206,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6433,7 +8013,9 @@
   {
    "metric_id": "spending.universal_childcare_entitlement",
    "year": 2031,
-   "value": 1607433548.773115,
+   "value": 3846294804.2724795,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -6442,7 +8024,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2025,
-   "value": 379484.6813406944,
+   "value": 985445.4297113419,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6451,7 +8035,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2026,
-   "value": 386394.35359191895,
+   "value": 988718.9267745018,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6460,7 +8046,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2027,
-   "value": 388693.47555303574,
+   "value": 992135.8684687614,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6469,7 +8057,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2028,
-   "value": 390652.560110569,
+   "value": 996884.7139797211,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6478,7 +8068,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2029,
-   "value": 404320.32845020294,
+   "value": 1001194.633936882,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6487,7 +8079,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2030,
-   "value": 406727.4603328705,
+   "value": 1010204.9373459816,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6496,7 +8090,9 @@
   {
    "metric_id": "caseloads.universal_childcare_entitlement",
    "year": 2031,
-   "value": 408660.8797736168,
+   "value": 1013771.0637845993,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -6505,7 +8101,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2025,
-   "value": 443196400.7338863,
+   "value": 572024783.1285633,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6514,7 +8112,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2026,
-   "value": 460006640.4923033,
+   "value": 593721428.6371526,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6523,7 +8123,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2027,
-   "value": 472326964.79148394,
+   "value": 609623032.498304,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6532,7 +8134,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2028,
-   "value": 483699822.07395244,
+   "value": 624301765.4036878,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6541,7 +8145,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2029,
-   "value": 495544205.88908577,
+   "value": 639589086.6096659,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6550,7 +8156,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2030,
-   "value": 497331070.06473446,
+   "value": 655315201.2710408,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6559,7 +8167,9 @@
   {
    "metric_id": "spending.targeted_childcare_entitlement",
    "year": 2031,
-   "value": 504378844.1796443,
+   "value": 664824494.3626773,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -6568,7 +8178,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2025,
-   "value": 91615.18099975586,
+   "value": 119291.62903356552,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6577,7 +8189,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2026,
-   "value": 91963.32138204575,
+   "value": 119744.94127082825,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6586,7 +8200,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2027,
-   "value": 92303.58706235886,
+   "value": 120188.00064563751,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6595,7 +8211,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2028,
-   "value": 92672.79612493515,
+   "value": 120668.74804401398,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6604,7 +8222,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2029,
-   "value": 93080.55707216263,
+   "value": 121199.69331502914,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6613,7 +8233,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2030,
-   "value": 91584.69786310196,
+   "value": 121745.09483098984,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6622,7 +8244,9 @@
   {
    "metric_id": "caseloads.targeted_childcare_entitlement",
    "year": 2031,
-   "value": 91061.30740070343,
+   "value": 121100.23704528809,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -6632,6 +8256,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6641,6 +8267,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6650,6 +8278,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6659,6 +8289,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6668,6 +8300,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6677,6 +8311,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6686,6 +8322,8 @@
    "metric_id": "spending.care_to_learn",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -6695,6 +8333,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6704,6 +8344,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6713,6 +8355,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6722,6 +8366,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6731,6 +8377,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6740,6 +8388,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6749,6 +8399,8 @@
    "metric_id": "caseloads.care_to_learn",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -6758,6 +8410,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6767,6 +8421,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6776,6 +8432,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6785,6 +8443,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6794,6 +8454,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6803,6 +8465,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6812,6 +8476,8 @@
    "metric_id": "spending.childcare_grant",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -6821,6 +8487,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6830,6 +8498,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6839,6 +8509,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6848,6 +8520,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6857,6 +8531,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6866,6 +8542,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6875,6 +8553,8 @@
    "metric_id": "caseloads.childcare_grant",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -6883,7 +8563,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2025,
-   "value": 200089205.6251793,
+   "value": 199163916.0120163,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6892,7 +8574,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2026,
-   "value": 200849551.41910172,
+   "value": 199920745.4944954,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6901,7 +8585,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2027,
-   "value": 201592698.65725708,
+   "value": 200660457.07904816,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6910,7 +8596,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2028,
-   "value": 202399059.3290062,
+   "value": 201463089.27254868,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6919,7 +8607,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2029,
-   "value": 203289618.08014297,
+   "value": 202349531.5649414,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6928,7 +8618,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2030,
-   "value": 167103353.08280182,
+   "value": 203188174.47846603,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6937,7 +8629,9 @@
   {
    "metric_id": "spending.parents_learning_allowance",
    "year": 2031,
-   "value": 167822216.12641907,
+   "value": 204061882.82292938,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -6946,7 +8640,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2025,
-   "value": 98858.3031744957,
+   "value": 98401.14427471161,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -6955,7 +8651,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2026,
-   "value": 99233.96809244156,
+   "value": 98775.07188463211,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -6964,7 +8662,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2027,
-   "value": 99601.13570022583,
+   "value": 99140.54203510284,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -6973,7 +8673,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2028,
-   "value": 99999.53524160385,
+   "value": 99537.09944295883,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -6982,7 +8684,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2029,
-   "value": 100439.53462457657,
+   "value": 99975.0650024414,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -6991,7 +8695,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2030,
-   "value": 82560.94519901276,
+   "value": 100389.41426801682,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -7000,7 +8706,9 @@
   {
    "metric_id": "caseloads.parents_learning_allowance",
    "year": 2031,
-   "value": 82916.11468696594,
+   "value": 100821.0883512497,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -7009,7 +8717,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2025,
-   "value": 37181344.76393461,
+   "value": 62362242.98413515,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7018,7 +8728,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2026,
-   "value": 37322635.825378895,
+   "value": 62599222.553822994,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7027,7 +8739,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2027,
-   "value": 37460730.62564373,
+   "value": 44187742.20506668,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7036,7 +8750,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2028,
-   "value": 37610571.710464954,
+   "value": 44364490.80733061,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7045,7 +8761,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2029,
-   "value": 37776058.51188898,
+   "value": 44559696.51651859,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7054,7 +8772,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2030,
-   "value": 37946051.452560425,
+   "value": 44760217.169840336,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7063,7 +8783,9 @@
   {
    "metric_id": "spending.adult_dependants_grant",
    "year": 2031,
-   "value": 38109291.55965805,
+   "value": 44952685.864076614,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -7072,7 +8794,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2025,
-   "value": 10488.390624523163,
+   "value": 17591.605919361115,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7081,7 +8805,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2026,
-   "value": 10528.247059345245,
+   "value": 17658.454881191254,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7090,7 +8816,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2027,
-   "value": 10567.201869010925,
+   "value": 12464.807392120361,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7099,7 +8827,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2028,
-   "value": 10609.470158100128,
+   "value": 12514.665954113007,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7108,7 +8838,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2029,
-   "value": 10656.151907444,
+   "value": 12569.73103427887,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7117,7 +8849,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2030,
-   "value": 10704.104782104492,
+   "value": 12626.29539346695,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7126,7 +8860,9 @@
   {
    "metric_id": "caseloads.adult_dependants_grant",
    "year": 2031,
-   "value": 10750.152767181396,
+   "value": 12680.588396072388,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -7136,6 +8872,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7145,6 +8883,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7154,6 +8894,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7163,6 +8905,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7172,6 +8916,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7181,6 +8927,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7190,6 +8938,8 @@
    "metric_id": "spending.travel_grant",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -7199,6 +8949,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7208,6 +8960,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7217,6 +8971,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7226,6 +8982,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7235,6 +8993,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7244,6 +9004,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7253,6 +9015,8 @@
    "metric_id": "caseloads.travel_grant",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -7261,7 +9025,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2025,
-   "value": 31398271.13342285,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7270,7 +9036,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2026,
-   "value": 31517584.991455078,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7279,7 +9047,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2027,
-   "value": 31634201.431274414,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7288,7 +9058,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2028,
-   "value": 31760736.053466797,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7297,7 +9069,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2029,
-   "value": 31900483.795166016,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7306,7 +9080,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2030,
-   "value": 32044037.338256836,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7315,7 +9091,9 @@
   {
    "metric_id": "spending.disabled_students_allowance",
    "year": 2031,
-   "value": 32181888.01574707,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -7324,7 +9102,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2025,
-   "value": 1744.3483963012695,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7333,7 +9113,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2026,
-   "value": 1750.9769439697266,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7342,7 +9124,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2027,
-   "value": 1757.4556350708008,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7351,7 +9135,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2028,
-   "value": 1764.485336303711,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7360,7 +9146,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2029,
-   "value": 1772.2490997314453,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7369,7 +9157,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2030,
-   "value": 1780.2242965698242,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7378,7 +9168,9 @@
   {
    "metric_id": "caseloads.disabled_students_allowance",
    "year": 2031,
-   "value": 1787.882667541504,
+   "value": null,
+   "suppressed": true,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -7388,6 +9180,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7397,6 +9191,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7406,6 +9202,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7415,6 +9213,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7424,6 +9224,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7433,6 +9235,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7442,6 +9246,8 @@
    "metric_id": "spending.bursary_fund_16_to_19",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -7451,6 +9257,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7460,6 +9268,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7469,6 +9279,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7478,6 +9290,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7487,6 +9301,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7496,6 +9312,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7505,6 +9323,8 @@
    "metric_id": "caseloads.bursary_fund_16_to_19",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -7513,7 +9333,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2025,
-   "value": 205232332361.1096,
+   "value": 204681602159.08142,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7522,7 +9344,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2026,
-   "value": 206012222586.4446,
+   "value": 205459399297.22324,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7531,7 +9355,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2027,
-   "value": 206774471228.05975,
+   "value": 206219602604.32385,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7540,7 +9366,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2028,
-   "value": 207601558499.668,
+   "value": 207044470471.60086,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7549,7 +9377,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2029,
-   "value": 208515008515.17273,
+   "value": 207955469002.00323,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7558,7 +9388,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2030,
-   "value": 209453332677.40167,
+   "value": 208891275075.5078,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7567,7 +9399,9 @@
   {
    "metric_id": "spending.nhs_spending",
    "year": 2031,
-   "value": 210354381149.51398,
+   "value": 209789506836.96567,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -7576,7 +9410,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2025,
-   "value": 33304098.421608984,
+   "value": 23991604.347275984,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7585,7 +9421,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2026,
-   "value": 33430655.237596173,
+   "value": 24082773.488280036,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7594,7 +9432,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2027,
-   "value": 33554349.3340033,
+   "value": 24171879.76151417,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7603,7 +9443,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2028,
-   "value": 33688564.45852884,
+   "value": 24268565.8560597,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7612,7 +9454,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2029,
-   "value": 33836794.51014231,
+   "value": 24375348.2293824,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7621,7 +9465,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2030,
-   "value": 33989060.95758362,
+   "value": 24485037.725156102,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7630,7 +9476,9 @@
   {
    "metric_id": "spending.dfe_education_spending",
    "year": 2031,
-   "value": 34135278.81945166,
+   "value": 24590323.320610803,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -7639,7 +9487,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2025,
-   "value": 25151126510.800682,
+   "value": 25151126494.365833,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7648,7 +9498,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2026,
-   "value": 25246701591.88542,
+   "value": 25246701555.2342,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7657,7 +9509,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2027,
-   "value": 25340114855.52831,
+   "value": 25340114784.780163,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7666,7 +9520,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2028,
-   "value": 25441474019.590816,
+   "value": 25441473946.770885,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7675,7 +9531,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2029,
-   "value": 25553416910.70827,
+   "value": 25553416805.737003,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7684,7 +9542,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2030,
-   "value": 25668408066.936726,
+   "value": 25668407910.982876,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7693,7 +9553,9 @@
   {
    "metric_id": "spending.dft_subsidy_spending",
    "year": 2031,
-   "value": 30944615266.675636,
+   "value": 25778782013.14279,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -7703,6 +9565,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7712,6 +9576,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7721,6 +9587,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7730,6 +9598,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7739,6 +9609,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7748,6 +9620,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7757,6 +9631,8 @@
    "metric_id": "spending.cost_of_living_support_payment",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -7766,6 +9642,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7775,6 +9653,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7784,6 +9664,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7793,6 +9675,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7802,6 +9686,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7811,6 +9697,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7820,6 +9708,8 @@
    "metric_id": "caseloads.cost_of_living_support_payment",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -7829,6 +9719,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7838,6 +9730,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7847,6 +9741,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7856,6 +9752,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7865,6 +9763,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7874,6 +9774,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7883,6 +9785,8 @@
    "metric_id": "spending.energy_bills_rebate",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -7892,6 +9796,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7901,6 +9807,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7910,6 +9818,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7919,6 +9829,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7928,6 +9840,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7937,6 +9851,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7946,6 +9862,8 @@
    "metric_id": "caseloads.energy_bills_rebate",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -7955,6 +9873,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -7964,6 +9884,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -7973,6 +9895,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -7982,6 +9906,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -7991,6 +9917,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -8000,6 +9928,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -8009,6 +9939,8 @@
    "metric_id": "spending.epg_subsidy",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -8018,6 +9950,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8027,6 +9961,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8036,6 +9972,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8045,6 +9983,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8054,6 +9994,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8063,6 +10005,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8072,6 +10016,8 @@
    "metric_id": "caseloads.epg_subsidy",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -8081,6 +10027,8 @@
    "metric_id": "spending.basic_income",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8090,6 +10038,8 @@
    "metric_id": "spending.basic_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8099,6 +10049,8 @@
    "metric_id": "spending.basic_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8108,6 +10060,8 @@
    "metric_id": "spending.basic_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8117,6 +10071,8 @@
    "metric_id": "spending.basic_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8126,6 +10082,8 @@
    "metric_id": "spending.basic_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8135,6 +10093,8 @@
    "metric_id": "spending.basic_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -8144,6 +10104,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8153,6 +10115,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8162,6 +10126,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8171,6 +10137,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8180,6 +10148,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8189,6 +10159,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8198,6 +10170,8 @@
    "metric_id": "caseloads.basic_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -8207,6 +10181,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8216,6 +10192,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8225,6 +10203,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8234,6 +10214,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8243,6 +10225,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8252,6 +10236,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8261,6 +10247,8 @@
    "metric_id": "spending.disability_basic_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -8270,6 +10258,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8279,6 +10269,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8288,6 +10280,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8297,6 +10291,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8306,6 +10302,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8315,6 +10313,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8324,6 +10324,8 @@
    "metric_id": "caseloads.disability_basic_income",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -8333,6 +10335,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2025,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8342,6 +10346,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2026,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8351,6 +10357,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2027,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8360,6 +10368,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2028,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8369,6 +10379,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2029,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8378,6 +10390,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2030,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8387,6 +10401,8 @@
    "metric_id": "spending.other_public_spending_budget_change",
    "year": 2031,
    "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -8395,7 +10411,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2025,
-   "value": 3130000070.860857,
+   "value": 3130000159.912464,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8404,7 +10422,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2026,
-   "value": 3129999934.869108,
+   "value": 3130000023.6063724,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8413,7 +10433,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2027,
-   "value": 3129999659.4758515,
+   "value": 3129999836.909186,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8422,7 +10444,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2028,
-   "value": 3129999971.286581,
+   "value": 3129999962.584343,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8431,7 +10455,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2029,
-   "value": 3129999604.8102255,
+   "value": 3129999544.0565424,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8440,7 +10466,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2030,
-   "value": 3129999725.6754894,
+   "value": 3129999895.007397,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8449,7 +10477,9 @@
   {
    "metric_id": "double_counts.corporate_sdlt",
    "year": 2031,
-   "value": 3129999838.862631,
+   "value": 3129999484.877694,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -8458,7 +10488,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2025,
-   "value": 978966763914.5134,
+   "value": 969745776128.1699,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8467,7 +10499,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2026,
-   "value": 1021443831661.053,
+   "value": 1011784948712.7561,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8476,7 +10510,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2027,
-   "value": 1060540354380.0239,
+   "value": 1050610465294.2213,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8485,7 +10521,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2028,
-   "value": 1096036577748.5464,
+   "value": 1085614034747.1652,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8494,7 +10532,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2029,
-   "value": 1133645091567.8396,
+   "value": 1124265122009.6616,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8503,7 +10543,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2030,
-   "value": 1172964045336.6704,
+   "value": 1163453498626.6191,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8512,7 +10554,9 @@
   {
    "metric_id": "model.gov_tax",
    "year": 2031,
-   "value": 1217259329604.8296,
+   "value": 1206982869582.7024,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8521,7 +10565,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2025,
-   "value": 507289555585.61816,
+   "value": 503977430092.485,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8530,7 +10576,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2026,
-   "value": 534626593895.75964,
+   "value": 531055850973.52136,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8539,7 +10587,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2027,
-   "value": 560967047377.9646,
+   "value": 557277774892.158,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8548,7 +10598,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2028,
-   "value": 583794322841.5969,
+   "value": 579764609886.5848,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8557,7 +10609,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2029,
-   "value": 606736767704.2439,
+   "value": 603325541929.8473,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8566,7 +10620,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2030,
-   "value": 631883079371.0518,
+   "value": 628508152120.9532,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8575,7 +10631,9 @@
   {
    "metric_id": "model.household_tax",
    "year": 2031,
-   "value": 660238702302.3933,
+   "value": 656263699478.5581,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8584,7 +10642,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2025,
-   "value": 499459280987.149,
+   "value": 496150814427.7457,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8593,7 +10653,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2026,
-   "value": 526499323434.2302,
+   "value": 522932377454.86273,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8602,7 +10664,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2027,
-   "value": 552613929618.1678,
+   "value": 548928559890.4607,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8611,7 +10675,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2028,
-   "value": 574737815078.9714,
+   "value": 570722062751.3651,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8620,7 +10686,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2029,
-   "value": 597441283752.3987,
+   "value": 594044368863.5272,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8629,7 +10697,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2030,
-   "value": 622323704519.8606,
+   "value": 618963456079.3445,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8638,7 +10708,9 @@
   {
    "metric_id": "model.pre_budget_change_household_tax",
    "year": 2031,
-   "value": 651647666882.8048,
+   "value": 646366448427.6294,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8647,7 +10719,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2025,
-   "value": 538033639372.52985,
+   "value": 536882494246.02844,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8656,7 +10732,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2026,
-   "value": 552208058548.4539,
+   "value": 551017143116.2849,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8665,7 +10745,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2027,
-   "value": 559025643057.2411,
+   "value": 557190195649.4889,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8674,7 +10758,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2028,
-   "value": 566053472893.2496,
+   "value": 564067532600.854,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8683,7 +10771,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2029,
-   "value": 574523316911.5459,
+   "value": 572364658929.4899,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8692,7 +10784,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2030,
-   "value": 579305085703.9962,
+   "value": 577022180786.2144,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8701,7 +10797,11 @@
   {
    "metric_id": "model.gov_spending",
    "year": 2031,
-   "value": 589946933468.4061,
+   "value": 586109747489.8334,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8710,7 +10810,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2025,
-   "value": 538389684305.1851,
+   "value": 536882494246.02844,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8719,7 +10823,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2026,
-   "value": 552578598164.1414,
+   "value": 551017143116.2849,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8728,7 +10836,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2027,
-   "value": 559406220932.2922,
+   "value": 557190195649.4889,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8737,7 +10849,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2028,
-   "value": 566443704502.9469,
+   "value": 564067532600.854,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8746,7 +10862,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2029,
-   "value": 574919476375.7018,
+   "value": 572364658929.4899,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8755,7 +10875,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2030,
-   "value": 579709866219.54,
+   "value": 577022180786.2144,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8764,7 +10888,11 @@
   {
    "metric_id": "model.household_benefits",
    "year": 2031,
-   "value": 590354941802.2732,
+   "value": 586109747489.8334,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -8773,7 +10901,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2025,
-   "value": 975836764403.4154,
+   "value": 966615777128.9729,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8782,7 +10912,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2026,
-   "value": 1018313832613.0851,
+   "value": 1008654948197.3245,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8791,7 +10923,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2027,
-   "value": 1057410354079.6709,
+   "value": 1047480466355.038,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8800,7 +10934,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2028,
-   "value": 1092906577896.0876,
+   "value": 1082484034898.3741,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8809,7 +10945,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2029,
-   "value": 1130515092103.1807,
+   "value": 1121135120971.1062,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8818,7 +10956,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2030,
-   "value": 1169834045361.7195,
+   "value": 1160323499762.114,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8827,7 +10967,9 @@
   {
    "metric_id": "balance.receipts",
    "year": 2031,
-   "value": 1214129326993.4458,
+   "value": 1203852872416.6934,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8836,7 +10978,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2025,
-   "value": 538033639676.7738,
+   "value": 536882494246.02844,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8845,7 +10991,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2026,
-   "value": 552208059037.354,
+   "value": 551017143116.2849,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8854,7 +11004,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2027,
-   "value": 559025643307.1086,
+   "value": 557190195649.4889,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8863,7 +11017,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2028,
-   "value": 566053472435.6144,
+   "value": 564067532600.854,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8872,7 +11030,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2029,
-   "value": 574523317043.8452,
+   "value": 572364658929.4899,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8881,7 +11043,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2030,
-   "value": 579305085287.3065,
+   "value": 577022180786.2144,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8890,7 +11056,11 @@
   {
    "metric_id": "balance.spending",
    "year": 2031,
-   "value": 589946932722.4471,
+   "value": 586109747489.8334,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8899,7 +11069,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2025,
-   "value": 437803124726.64154,
+   "value": 429733282882.94446,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8908,7 +11082,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2026,
-   "value": 466105773575.731,
+   "value": 457637805081.0396,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8917,7 +11095,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2027,
-   "value": 498384710772.5623,
+   "value": 490290270705.5491,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8926,7 +11108,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2028,
-   "value": 526853105460.47296,
+   "value": 518416502297.52026,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8935,7 +11121,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2029,
-   "value": 555991775059.3357,
+   "value": 548770462041.61646,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8944,7 +11134,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2030,
-   "value": 590528960074.4128,
+   "value": 583301318975.8997,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8953,7 +11147,11 @@
   {
    "metric_id": "balance.balance",
    "year": 2031,
-   "value": 624182394270.9988,
+   "value": 617743124926.8599,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8962,7 +11160,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2025,
-   "value": 551697696.1319505,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8971,7 +11171,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2026,
-   "value": 573788727.0823206,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8980,7 +11182,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2027,
-   "value": 587932937.3870641,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8989,7 +11193,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2028,
-   "value": 601425544.379385,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -8998,7 +11204,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2029,
-   "value": 612524542.784497,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -9007,7 +11215,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2030,
-   "value": 626466307.2763597,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -9016,7 +11226,9 @@
   {
    "metric_id": "balance.household_only_benefits",
    "year": 2031,
-   "value": 635100657.4934409,
+   "value": 0.0,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -9025,7 +11237,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2025,
-   "value": 440933124873.35913,
+   "value": 432863283042.85693,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9034,7 +11250,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2026,
-   "value": 469235773431.7386,
+   "value": 460767805104.64594,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9043,7 +11263,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2027,
-   "value": 501514711424.7265,
+   "value": 493420270542.4583,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9052,7 +11276,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2028,
-   "value": 529983106859.2174,
+   "value": 521546502260.1046,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9061,7 +11289,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2029,
-   "value": 559121775135.3358,
+   "value": 551900461585.6729,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9070,7 +11302,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2030,
-   "value": 593658959431.4342,
+   "value": 586431318870.907,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9079,7 +11315,11 @@
   {
    "metric_id": "model.gov_balance",
    "year": 2031,
-   "value": 627312396103.4205,
+   "value": 620873124411.7375,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -9088,7 +11328,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2025,
-   "value": 1671225658932.162,
+   "value": 1657055494245.5037,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9097,7 +11339,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2026,
-   "value": 1733933903918.711,
+   "value": 1719245701089.3281,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9106,7 +11350,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2027,
-   "value": 1786792811393.0068,
+   "value": 1771683231648.2764,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9115,7 +11361,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2028,
-   "value": 1837490253867.1548,
+   "value": 1821985672731.2063,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9124,7 +11372,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2029,
-   "value": 1899443273442.607,
+   "value": 1887412879505.8608,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9133,7 +11383,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2030,
-   "value": 1958070419692.7725,
+   "value": 1945587770944.968,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9142,7 +11394,9 @@
   {
    "metric_id": "household.household_market_income",
    "year": 2031,
-   "value": 2030307938225.9048,
+   "value": 2017368706417.267,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9151,7 +11405,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2025,
-   "value": 1662845456756.1794,
+   "value": 1650695092699.1787,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9160,7 +11418,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2026,
-   "value": 1710908123095.9045,
+   "value": 1698452218971.148,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9169,7 +11431,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2027,
-   "value": 1743115474011.6213,
+   "value": 1729708349505.7048,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9178,7 +11444,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2028,
-   "value": 1776966674392.025,
+   "value": 1763350595681.0042,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9187,7 +11457,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2029,
-   "value": 1812648751541.618,
+   "value": 1797840584674.6392,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9196,7 +11470,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2030,
-   "value": 1849604189724.0015,
+   "value": 1834164055321.444,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9205,7 +11483,11 @@
   {
    "metric_id": "household.household_net_income",
    "year": 2031,
-   "value": 1901814852667.9023,
+   "value": 1884778958157.876,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9214,7 +11496,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2025,
-   "value": 1477497599801.4927,
+   "value": 1468438454639.119,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9223,7 +11507,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2026,
-   "value": 1524365447451.7742,
+   "value": 1515139365275.6355,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9232,7 +11518,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2027,
-   "value": 1557424708805.0208,
+   "value": 1547358223256.206,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9241,7 +11529,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2028,
-   "value": 1590631579327.68,
+   "value": 1580410096999.486,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9250,7 +11540,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2029,
-   "value": 1624770529416.2014,
+   "value": 1613429021347.468,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9259,7 +11551,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2030,
-   "value": 1659800503787.3513,
+   "value": 1647838190515.2617,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9268,7 +11562,9 @@
   {
    "metric_id": "household.hbai_household_net_income",
    "year": 2031,
-   "value": 1706265955643.35,
+   "value": 1697900004504.373,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -9277,7 +11573,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2025,
-   "value": 0.15790499791115192,
+   "value": 0.158961068989031,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9286,7 +11584,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2026,
-   "value": 0.15015054717546153,
+   "value": 0.149417048095037,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9295,7 +11595,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2027,
-   "value": 0.1549582355031067,
+   "value": 0.1551359605887892,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9304,7 +11606,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2028,
-   "value": 0.15586605016301394,
+   "value": 0.15590985583220196,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9313,7 +11617,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2029,
-   "value": 0.15679856209322698,
+   "value": 0.15717923007921353,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9322,7 +11628,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2030,
-   "value": 0.15996963062767566,
+   "value": 0.1610142002033216,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9331,7 +11639,9 @@
   {
    "metric_id": "poverty.absolute_bhc.all",
    "year": 2031,
-   "value": 0.15916276272552643,
+   "value": 0.1599545027297433,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9340,7 +11650,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2025,
-   "value": 11008006.535612345,
+   "value": 11050012.62085329,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9349,7 +11661,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2026,
-   "value": 10507198.299471915,
+   "value": 10426039.302517518,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9358,7 +11672,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2027,
-   "value": 10883751.14921306,
+   "value": 10865147.24560164,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9367,7 +11683,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2028,
-   "value": 10991302.525305092,
+   "value": 10963024.831684813,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9376,7 +11694,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2029,
-   "value": 11105712.280909285,
+   "value": 11100912.898740932,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9385,7 +11705,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2030,
-   "value": 11381299.168434069,
+   "value": 11422934.10709335,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9394,7 +11716,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.all",
    "year": 2031,
-   "value": 11372607.559264764,
+   "value": 11396550.62013276,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9403,7 +11727,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2025,
-   "value": 0.23024237894583952,
+   "value": 0.2372510378251411,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9412,7 +11738,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2026,
-   "value": 0.20587063573611564,
+   "value": 0.20852661548421755,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9421,7 +11749,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2027,
-   "value": 0.21312205523439626,
+   "value": 0.21671681039197135,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9430,7 +11760,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2028,
-   "value": 0.21148974274821794,
+   "value": 0.21457714000706526,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9439,7 +11771,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2029,
-   "value": 0.2129381736428246,
+   "value": 0.21642597560772944,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9448,7 +11782,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2030,
-   "value": 0.2171366623415043,
+   "value": 0.2217104975392767,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9457,7 +11793,9 @@
   {
    "metric_id": "poverty.absolute_bhc.children",
    "year": 2031,
-   "value": 0.2168645562087503,
+   "value": 0.22078118293404653,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9466,7 +11804,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2025,
-   "value": 3458586.670649603,
+   "value": 3559375.146835327,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9475,7 +11815,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2026,
-   "value": 3104238.0042080134,
+   "value": 3140323.1707639247,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9484,7 +11826,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2027,
-   "value": 3225469.4537050426,
+   "value": 3275739.6749524027,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9493,7 +11837,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2028,
-   "value": 3213568.3187645674,
+   "value": 3256371.3432342857,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9502,7 +11848,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2029,
-   "value": 3249813.6879644096,
+   "value": 3298880.366600305,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9511,7 +11859,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2030,
-   "value": 3328802.6769966334,
+   "value": 3394637.414582446,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9520,7 +11870,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.children",
    "year": 2031,
-   "value": 3338933.418882489,
+   "value": 3394944.311651394,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9529,7 +11881,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2025,
-   "value": 0.13730515589263637,
+   "value": 0.13767748825105397,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9538,7 +11892,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2026,
-   "value": 0.13444889083444914,
+   "value": 0.13372106552488075,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9547,7 +11903,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2027,
-   "value": 0.13964335698946462,
+   "value": 0.13989204520959575,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9556,7 +11914,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2028,
-   "value": 0.14095635404241666,
+   "value": 0.14124164361087443,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9565,7 +11925,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2029,
-   "value": 0.14196947141222863,
+   "value": 0.14248707378049913,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9574,7 +11936,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2030,
-   "value": 0.1453637344339517,
+   "value": 0.14658630153368837,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9583,7 +11947,9 @@
   {
    "metric_id": "poverty.absolute_bhc.working_age_adults",
    "year": 2031,
-   "value": 0.1424988521749652,
+   "value": 0.14525417694146392,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9592,7 +11958,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2025,
-   "value": 5861346.487035349,
+   "value": 5863952.6221417785,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9601,7 +11969,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2026,
-   "value": 5780330.343414247,
+   "value": 5736660.92677407,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9610,7 +11980,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2027,
-   "value": 6067671.953066379,
+   "value": 6072487.460049972,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9619,7 +11991,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2028,
-   "value": 6169748.167899072,
+   "value": 6178484.984416798,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9628,7 +12002,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2029,
-   "value": 6241435.053964257,
+   "value": 6260390.306578115,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9637,7 +12013,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2030,
-   "value": 6419415.955847114,
+   "value": 6469478.6622083485,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9646,7 +12024,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.working_age_adults",
    "year": 2031,
-   "value": 6319971.187485427,
+   "value": 6438252.252475888,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9655,7 +12035,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2025,
-   "value": 0.14063908804109557,
+   "value": 0.13647330334302774,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9664,7 +12046,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2026,
-   "value": 0.13628217188144012,
+   "value": 0.13107228723131284,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9673,7 +12057,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2027,
-   "value": 0.1365202033742876,
+   "value": 0.13176164489560352,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9682,7 +12068,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2028,
-   "value": 0.1391945511558675,
+   "value": 0.13408989504529978,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9691,7 +12079,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2029,
-   "value": 0.1391430413120495,
+   "value": 0.13467956142673865,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9700,7 +12090,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2030,
-   "value": 0.14011702215368302,
+   "value": 0.13556998964969896,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9709,7 +12101,9 @@
   {
    "metric_id": "poverty.absolute_bhc.pensioners",
    "year": 2031,
-   "value": 0.14640454331430913,
+   "value": 0.13538234298373342,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9718,7 +12112,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2025,
-   "value": 1688073.3779273927,
+   "value": 1626684.8518761843,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9727,7 +12123,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2026,
-   "value": 1622629.9518496543,
+   "value": 1549055.204979524,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9736,7 +12134,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2027,
-   "value": 1590609.7424416393,
+   "value": 1516920.1105992645,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9745,7 +12145,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2028,
-   "value": 1607986.0386414528,
+   "value": 1528168.5040337294,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9754,7 +12156,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2029,
-   "value": 1614463.5389806181,
+   "value": 1541642.2255625129,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9763,7 +12167,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2030,
-   "value": 1633080.5355903208,
+   "value": 1558818.0303025544,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9772,7 +12178,9 @@
   {
    "metric_id": "poverty_count.absolute_bhc.pensioners",
    "year": 2031,
-   "value": 1713702.9528968483,
+   "value": 1563354.056005478,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9781,7 +12189,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2025,
-   "value": 0.2084922594723321,
+   "value": 0.20913249144654364,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9790,7 +12200,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2026,
-   "value": 0.2033983080431449,
+   "value": 0.20368321654160576,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9799,7 +12211,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2027,
-   "value": 0.2085258023862174,
+   "value": 0.2099396779334123,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9808,7 +12222,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2028,
-   "value": 0.21083623822359046,
+   "value": 0.21265695145642433,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9817,7 +12233,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2029,
-   "value": 0.21373904608988534,
+   "value": 0.2154006487190125,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9826,7 +12244,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2030,
-   "value": 0.2213187707909106,
+   "value": 0.22356054596434546,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9835,7 +12255,9 @@
   {
    "metric_id": "poverty.absolute_ahc.all",
    "year": 2031,
-   "value": 0.2195671141063277,
+   "value": 0.223770468364186,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9844,7 +12266,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2025,
-   "value": 14534588.42504394,
+   "value": 14537626.631551296,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9853,7 +12277,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2026,
-   "value": 14233357.097853199,
+   "value": 14212630.00441049,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9862,7 +12288,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2027,
-   "value": 14646158.908514857,
+   "value": 14703396.329152241,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9871,7 +12299,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2028,
-   "value": 14867669.227449715,
+   "value": 14953278.142699987,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9880,7 +12310,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2029,
-   "value": 15138686.971242383,
+   "value": 15212848.660455883,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9889,7 +12321,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2030,
-   "value": 15746083.378938913,
+   "value": 15860199.797730953,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9898,7 +12332,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.all",
    "year": 2031,
-   "value": 15688660.958704859,
+   "value": 15943355.307177946,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9907,7 +12343,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2025,
-   "value": 0.31720685844300495,
+   "value": 0.3176647822027365,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9916,7 +12354,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2026,
-   "value": 0.30038158814530413,
+   "value": 0.29976792277040976,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9925,7 +12365,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2027,
-   "value": 0.3065600330656107,
+   "value": 0.3075246154957757,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9934,7 +12376,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2028,
-   "value": 0.3089024392477794,
+   "value": 0.31040394928891696,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9943,7 +12387,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2029,
-   "value": 0.3131465359163617,
+   "value": 0.31404388184177656,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9952,7 +12398,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2030,
-   "value": 0.32764715169339104,
+   "value": 0.32925032071219956,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9961,7 +12409,9 @@
   {
    "metric_id": "poverty.absolute_ahc.children",
    "year": 2031,
-   "value": 0.32587820140005935,
+   "value": 0.3295364201437651,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -9970,7 +12420,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2025,
-   "value": 4764923.892259136,
+   "value": 4765787.92304638,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9979,7 +12431,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2026,
-   "value": 4529329.490584716,
+   "value": 4514378.90334405,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9988,7 +12442,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2027,
-   "value": 4639595.002462,
+   "value": 4648326.921118781,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -9997,7 +12453,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2028,
-   "value": 4693745.802781373,
+   "value": 4710616.076148167,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10006,7 +12464,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2029,
-   "value": 4779170.786289513,
+   "value": 4786824.655172229,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10015,7 +12475,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2030,
-   "value": 5022978.173772946,
+   "value": 5041193.222052559,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10024,7 +12486,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.children",
    "year": 2031,
-   "value": 5017351.0884489715,
+   "value": 5067269.683862701,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10033,7 +12497,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2025,
-   "value": 0.19375179335562778,
+   "value": 0.19431403398519395,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10042,7 +12508,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2026,
-   "value": 0.1915301826384273,
+   "value": 0.19237286661348602,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10051,7 +12519,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2027,
-   "value": 0.19779351466886932,
+   "value": 0.1997992793069061,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10060,7 +12530,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2028,
-   "value": 0.19985745387449372,
+   "value": 0.20238185535311953,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10069,7 +12541,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2029,
-   "value": 0.20299186364561206,
+   "value": 0.20530273277647584,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10078,7 +12552,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2030,
-   "value": 0.21009860237041597,
+   "value": 0.2131128866367783,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10087,7 +12563,9 @@
   {
    "metric_id": "poverty.absolute_ahc.working_age_adults",
    "year": 2031,
-   "value": 0.205233615867211,
+   "value": 0.21322897588420822,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10096,7 +12574,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2025,
-   "value": 8270966.854513526,
+   "value": 8276213.515957296,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10105,7 +12585,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2026,
-   "value": 8234413.236980796,
+   "value": 8252835.130660608,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10114,7 +12596,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2027,
-   "value": 8594366.300899416,
+   "value": 8672963.61491029,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10123,7 +12607,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2028,
-   "value": 8747886.310340255,
+   "value": 8853006.963460386,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10132,7 +12618,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2029,
-   "value": 8924175.886719018,
+   "value": 9020293.589352593,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10141,7 +12629,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2030,
-   "value": 9278176.056839228,
+   "value": 9405580.591863185,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10150,7 +12640,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.working_age_adults",
    "year": 2031,
-   "value": 9102322.714793772,
+   "value": 9451170.101861268,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10159,7 +12651,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2025,
-   "value": 0.1248615596202156,
+   "value": 0.12547784554248842,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10168,7 +12662,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2026,
-   "value": 0.12343063061462466,
+   "value": 0.12230292156970884,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10177,7 +12673,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2027,
-   "value": 0.12120729498631465,
+   "value": 0.12005149872375881,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10186,7 +12684,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2028,
-   "value": 0.12344422855077232,
+   "value": 0.12193596873043704,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10195,7 +12695,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2029,
-   "value": 0.12370524920005636,
+   "value": 0.12280615616424372,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10204,7 +12706,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2030,
-   "value": 0.12397378149719714,
+   "value": 0.1229252820223357,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10213,7 +12717,9 @@
   {
    "metric_id": "poverty.absolute_ahc.pensioners",
    "year": 2031,
-   "value": 0.13404122784123754,
+   "value": 0.12339393057336441,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10222,7 +12728,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2025,
-   "value": 1498697.6782712787,
+   "value": 1495625.1925476193,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10231,7 +12739,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2026,
-   "value": 1469614.3702876866,
+   "value": 1445415.970405832,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10240,7 +12750,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2027,
-   "value": 1412197.6051534414,
+   "value": 1382105.7931231707,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10249,7 +12761,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2028,
-   "value": 1426037.1143280864,
+   "value": 1389655.1030914336,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10258,7 +12772,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2029,
-   "value": 1435340.2982338518,
+   "value": 1405730.415931061,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10267,7 +12783,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2030,
-   "value": 1444929.1483267397,
+   "value": 1413425.983815208,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10276,7 +12794,9 @@
   {
    "metric_id": "poverty_count.absolute_ahc.pensioners",
    "year": 2031,
-   "value": 1568987.155462116,
+   "value": 1424915.5214539766,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10285,7 +12805,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2025,
-   "value": 0.17062007668867718,
+   "value": 0.16996315965340555,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10294,7 +12816,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2026,
-   "value": 0.1647051950949729,
+   "value": 0.1641757039106901,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10303,7 +12827,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2027,
-   "value": 0.1644876206126917,
+   "value": 0.1658306356282735,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10312,7 +12838,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2028,
-   "value": 0.16684150829295824,
+   "value": 0.16675706960047298,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10321,7 +12849,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2029,
-   "value": 0.1684367435335271,
+   "value": 0.16818506457390087,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10330,7 +12860,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2030,
-   "value": 0.1631533914075491,
+   "value": 0.16603686894151898,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10339,7 +12871,9 @@
   {
    "metric_id": "poverty.relative_bhc.all",
    "year": 2031,
-   "value": 0.169943728112801,
+   "value": 0.16939429823668872,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10348,7 +12882,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2025,
-   "value": 11894410.842856497,
+   "value": 11814811.457891181,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10357,7 +12893,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2026,
-   "value": 11525699.895011187,
+   "value": 11455870.419837251,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10366,7 +12904,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2027,
-   "value": 11553063.469406977,
+   "value": 11614162.616421178,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10375,7 +12915,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2028,
-   "value": 11765265.684914708,
+   "value": 11725762.204902157,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10384,7 +12926,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2029,
-   "value": 11930020.187968686,
+   "value": 11878209.046851024,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10393,7 +12937,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2030,
-   "value": 11607812.999679968,
+   "value": 11779260.530264333,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10402,7 +12948,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.all",
    "year": 2031,
-   "value": 12142936.53797774,
+   "value": 12069123.79252024,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10411,7 +12959,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2025,
-   "value": 0.25579913589553366,
+   "value": 0.2576548985094404,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10420,7 +12970,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2026,
-   "value": 0.23345621726435167,
+   "value": 0.2349385317072657,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10429,7 +12981,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2027,
-   "value": 0.22912843225646004,
+   "value": 0.23473844147435505,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10438,7 +12992,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2028,
-   "value": 0.23084457664090657,
+   "value": 0.23360704801218143,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10447,7 +13003,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2029,
-   "value": 0.23197251050977175,
+   "value": 0.23495351453647773,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10456,7 +13014,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2030,
-   "value": 0.2220824501863291,
+   "value": 0.23174222961978033,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10465,7 +13025,9 @@
   {
    "metric_id": "poverty.relative_bhc.children",
    "year": 2031,
-   "value": 0.23445025294767866,
+   "value": 0.23914597293246234,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10474,7 +13036,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2025,
-   "value": 3842487.581228867,
+   "value": 3865485.4816306233,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10483,7 +13047,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2026,
-   "value": 3520189.556705728,
+   "value": 3538075.5262937695,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10492,7 +13058,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2027,
-   "value": 3467715.9921610057,
+   "value": 3548142.041142389,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10501,7 +13069,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2028,
-   "value": 3507663.3429688513,
+   "value": 3545164.6745751947,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10510,7 +13080,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2029,
-   "value": 3540311.3823575675,
+   "value": 3581287.015071422,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10519,7 +13091,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2030,
-   "value": 3404623.8287089914,
+   "value": 3548234.530783549,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10528,7 +13102,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.children",
    "year": 2031,
-   "value": 3609689.837369889,
+   "value": 3677339.0271395296,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10537,7 +13113,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2025,
-   "value": 0.14589881032453236,
+   "value": 0.14512498963363443,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10546,7 +13124,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2026,
-   "value": 0.14416151943670144,
+   "value": 0.14359366405754964,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10555,7 +13135,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2027,
-   "value": 0.1465298878616869,
+   "value": 0.1475713897931732,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10564,7 +13146,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2028,
-   "value": 0.14949165839067746,
+   "value": 0.1494918942688663,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10573,7 +13157,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2029,
-   "value": 0.15186122947304564,
+   "value": 0.1516084128453753,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10582,7 +13168,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2030,
-   "value": 0.14784727703111472,
+   "value": 0.1503840561165627,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10591,7 +13179,9 @@
   {
    "metric_id": "poverty.relative_bhc.working_age_adults",
    "year": 2031,
-   "value": 0.15069757220037083,
+   "value": 0.15254973464975796,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10600,7 +13190,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2025,
-   "value": 6228196.412573293,
+   "value": 6181156.224673748,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10609,7 +13201,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2026,
-   "value": 6197903.1584480405,
+   "value": 6160197.413159236,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10618,7 +13212,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2027,
-   "value": 6366900.008937746,
+   "value": 6405835.3899862915,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10627,7 +13223,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2028,
-   "value": 6543343.801262975,
+   "value": 6539384.56406565,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10636,7 +13234,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2029,
-   "value": 6676308.586224228,
+   "value": 6661150.467831269,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10645,7 +13245,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2030,
-   "value": 6529091.818519026,
+   "value": 6637089.76898399,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10654,7 +13256,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.working_age_adults",
    "year": 2031,
-   "value": 6683592.883688301,
+   "value": 6761620.8594070375,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10663,7 +13267,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2025,
-   "value": 0.15194083636457575,
+   "value": 0.14834340320557673,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10672,7 +13278,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2026,
-   "value": 0.15181812223954255,
+   "value": 0.14871795468967855,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10681,7 +13289,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2027,
-   "value": 0.1474923682419708,
+   "value": 0.14420583478126237,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10690,7 +13300,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2028,
-   "value": 0.14839398004790294,
+   "value": 0.14400903683858882,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10699,7 +13311,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2029,
-   "value": 0.1476699298274378,
+   "value": 0.14290280401894626,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10708,7 +13322,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2030,
-   "value": 0.14363623269573814,
+   "value": 0.1386242101836538,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10717,7 +13333,9 @@
   {
    "metric_id": "poverty.relative_bhc.pensioners",
    "year": 2031,
-   "value": 0.1580190556933559,
+   "value": 0.14116789999709253,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10726,7 +13344,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2025,
-   "value": 1823726.8490543365,
+   "value": 1768169.7515868098,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10735,7 +13355,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2026,
-   "value": 1807607.179857418,
+   "value": 1757597.4803842455,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10744,7 +13366,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2027,
-   "value": 1718447.4683082253,
+   "value": 1660185.1852924973,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10753,7 +13377,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2028,
-   "value": 1714258.540682882,
+   "value": 1641212.9662613124,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10762,7 +13388,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2029,
-   "value": 1713400.2193868905,
+   "value": 1635771.5639483333,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10771,7 +13399,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2030,
-   "value": 1674097.3524519503,
+   "value": 1593936.230496794,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10780,7 +13410,9 @@
   {
    "metric_id": "poverty_count.relative_bhc.pensioners",
    "year": 2031,
-   "value": 1849653.8169195503,
+   "value": 1630163.9059736729,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10789,7 +13421,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2025,
-   "value": 0.21330212332422502,
+   "value": 0.21456512996755925,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10798,7 +13432,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2026,
-   "value": 0.2105464759711648,
+   "value": 0.2108568153025047,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10807,7 +13443,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2027,
-   "value": 0.21119415618195903,
+   "value": 0.21280995156860974,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10816,7 +13454,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2028,
-   "value": 0.2124423499774284,
+   "value": 0.2141820445617756,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10825,7 +13465,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2029,
-   "value": 0.2140000786845929,
+   "value": 0.2155949209344568,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10834,7 +13476,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2030,
-   "value": 0.2204001169903213,
+   "value": 0.21996997492343381,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10843,7 +13487,9 @@
   {
    "metric_id": "poverty.relative_ahc.all",
    "year": 2031,
-   "value": 0.2194456696036841,
+   "value": 0.2227237561956704,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10852,7 +13498,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2025,
-   "value": 14869897.714917302,
+   "value": 14915270.822066262,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10861,7 +13509,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2026,
-   "value": 14733569.846394584,
+   "value": 14713190.171909258,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10870,7 +13520,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2027,
-   "value": 14833575.205535918,
+   "value": 14904419.64807345,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10879,7 +13531,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2028,
-   "value": 14980928.401961535,
+   "value": 15060517.248883188,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10888,7 +13542,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2029,
-   "value": 15157175.360766247,
+   "value": 15226569.296071708,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10897,7 +13553,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2030,
-   "value": 15680724.262363464,
+   "value": 15605471.6038488,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10906,7 +13564,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.all",
    "year": 2031,
-   "value": 15679983.42229405,
+   "value": 15868778.424316749,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10915,7 +13575,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2025,
-   "value": 0.3248406624741081,
+   "value": 0.32573092950864546,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10924,7 +13586,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2026,
-   "value": 0.3131278902007049,
+   "value": 0.3129215499802995,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10933,7 +13597,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2027,
-   "value": 0.30979319184398263,
+   "value": 0.31080197766773193,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10942,7 +13608,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2028,
-   "value": 0.3102686929501225,
+   "value": 0.3112443481181635,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10951,7 +13619,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2029,
-   "value": 0.3134903767691043,
+   "value": 0.31435135617461696,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10960,7 +13630,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2030,
-   "value": 0.3252235647703323,
+   "value": 0.32341397660487087,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10969,7 +13641,9 @@
   {
    "metric_id": "poverty.relative_ahc.children",
    "year": 2031,
-   "value": 0.3257920669222945,
+   "value": 0.32841073439755847,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -10978,7 +13652,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2025,
-   "value": 4879595.105218306,
+   "value": 4886800.85733974,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10987,7 +13663,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2026,
-   "value": 4721525.697256014,
+   "value": 4712466.999728724,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -10996,7 +13674,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2027,
-   "value": 4688526.845143169,
+   "value": 4697865.234627768,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11005,7 +13685,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2028,
-   "value": 4714505.909423858,
+   "value": 4723369.767731324,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11014,7 +13696,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2029,
-   "value": 4784418.406716645,
+   "value": 4791511.343251109,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11023,7 +13707,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2030,
-   "value": 4985823.496389523,
+   "value": 4951832.22069715,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11032,7 +13718,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.children",
    "year": 2031,
-   "value": 5016024.927589148,
+   "value": 5049960.054618016,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11041,7 +13729,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2025,
-   "value": 0.19713460206621386,
+   "value": 0.19817681755370278,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11050,7 +13740,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2026,
-   "value": 0.19751408902821108,
+   "value": 0.19800752646020686,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11059,7 +13751,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2027,
-   "value": 0.19980334977328973,
+   "value": 0.2018228258946827,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11068,7 +13762,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2028,
-   "value": 0.20092494834158509,
+   "value": 0.20314734474442595,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11077,7 +13773,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2029,
-   "value": 0.20323204364702235,
+   "value": 0.2054474903629614,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11086,7 +13784,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2030,
-   "value": 0.2095568415310035,
+   "value": 0.21027795561183132,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11095,7 +13795,9 @@
   {
    "metric_id": "poverty.relative_ahc.working_age_adults",
    "year": 2031,
-   "value": 0.2051403722499053,
+   "value": 0.2126635701601802,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11104,7 +13806,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2025,
-   "value": 8415373.769339144,
+   "value": 8440736.998503834,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11113,7 +13817,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2026,
-   "value": 8491677.952683121,
+   "value": 8494563.18488653,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11122,7 +13828,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2027,
-   "value": 8681696.055470556,
+   "value": 8760802.499964043,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11131,7 +13839,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2028,
-   "value": 8794611.213785172,
+   "value": 8886492.58844325,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11140,7 +13850,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2029,
-   "value": 8934734.972874314,
+   "value": 9026653.738152012,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11149,7 +13861,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2030,
-   "value": 9254251.326298147,
+   "value": 9280462.995042503,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11158,7 +13872,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.working_age_adults",
    "year": 2031,
-   "value": 9098187.264116138,
+   "value": 9426109.034751624,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11167,7 +13883,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2025,
-   "value": 0.1312126349091424,
+   "value": 0.133205373171771,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11176,7 +13894,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2026,
-   "value": 0.12769319774473814,
+   "value": 0.12744273660248256,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11185,7 +13905,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2027,
-   "value": 0.12559784398751747,
+   "value": 0.125579883146286,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11194,7 +13916,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2028,
-   "value": 0.12740664745148308,
+   "value": 0.12728842519447406,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11203,7 +13927,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2029,
-   "value": 0.12393637087688392,
+   "value": 0.12303974216451169,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11212,7 +13938,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2030,
-   "value": 0.1236065858698001,
+   "value": 0.119424785385011,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11221,7 +13949,9 @@
   {
    "metric_id": "poverty.relative_ahc.pensioners",
    "year": 2031,
-   "value": 0.13376648593709345,
+   "value": 0.12060495966103543,
+   "suppressed": false,
+   "excludes": [],
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11230,7 +13960,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2025,
-   "value": 1574928.8403598517,
+   "value": 1587732.9662226886,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11239,7 +13971,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2026,
-   "value": 1520366.1964554489,
+   "value": 1506159.9872940034,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11248,7 +13982,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2027,
-   "value": 1463352.3049221933,
+   "value": 1445751.9134816378,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11257,7 +13993,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2028,
-   "value": 1471811.2787525058,
+   "value": 1450654.8927086145,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11266,7 +14004,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2029,
-   "value": 1438021.9811752886,
+   "value": 1408404.2146685869,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11275,7 +14015,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2030,
-   "value": 1440649.439675793,
+   "value": 1373176.3881091475,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11284,7 +14026,9 @@
   {
    "metric_id": "poverty_count.relative_ahc.pensioners",
    "year": 2031,
-   "value": 1565771.230588764,
+   "value": 1392709.3349471092,
+   "suppressed": false,
+   "excludes": [],
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11293,7 +14037,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2025,
-   "value": 0.31169660677586286,
+   "value": 0.3077487914075191,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11302,7 +14048,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2026,
-   "value": 0.3094015441232131,
+   "value": 0.3054631654461407,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11311,7 +14059,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2027,
-   "value": 0.3105687571293162,
+   "value": 0.3069197698442653,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11320,7 +14070,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2028,
-   "value": 0.3112819865588672,
+   "value": 0.3077757166797609,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11329,7 +14081,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2029,
-   "value": 0.31188628846609523,
+   "value": 0.3082329014779346,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11338,7 +14092,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2030,
-   "value": 0.3137188460113969,
+   "value": 0.3099891970371004,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11347,7 +14103,9 @@
   {
    "metric_id": "inequality.gini_equiv_hbai_bhc",
    "year": 2031,
-   "value": 0.3126616094414172,
+   "value": 0.3110144570254967,
+   "suppressed": false,
+   "excludes": [],
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -11356,7 +14114,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2025,
-   "value": 18262.585926938675,
+   "value": 17676.754667048575,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11365,7 +14127,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2026,
-   "value": 18565.573452097553,
+   "value": 17959.072766481713,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11374,7 +14140,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2027,
-   "value": 18587.9409768735,
+   "value": 17890.694840247495,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11383,7 +14153,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2028,
-   "value": 18712.32311277851,
+   "value": 17941.1511777277,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11392,7 +14166,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2029,
-   "value": 19079.33376464379,
+   "value": 18267.238369432558,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11401,7 +14179,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2030,
-   "value": 19168.884477875916,
+   "value": 18350.30992490091,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11410,7 +14192,11 @@
   {
    "metric_id": "deciles.mean_income.1",
    "year": 2031,
-   "value": 19487.832363597438,
+   "value": 18550.46356681594,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11419,7 +14205,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2025,
-   "value": 28212.59715391376,
+   "value": 28179.055803438234,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11428,7 +14218,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2026,
-   "value": 29005.91280891695,
+   "value": 28837.04533117914,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11437,7 +14231,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2027,
-   "value": 28622.542707465953,
+   "value": 28424.564554846565,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11446,7 +14244,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2028,
-   "value": 28878.39944749893,
+   "value": 28883.45566735774,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11455,7 +14257,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2029,
-   "value": 29211.074914268487,
+   "value": 29061.95653619478,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11464,7 +14270,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2030,
-   "value": 29528.185297717675,
+   "value": 29759.483201387062,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11473,7 +14283,11 @@
   {
    "metric_id": "deciles.mean_income.2",
    "year": 2031,
-   "value": 30103.165466505827,
+   "value": 30221.58748982937,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11482,7 +14296,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2025,
-   "value": 34413.19157264763,
+   "value": 34530.61843120579,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11491,7 +14309,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2026,
-   "value": 35673.03127903994,
+   "value": 35774.3120618477,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11500,7 +14322,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2027,
-   "value": 36287.079062372846,
+   "value": 36424.80493358469,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11509,7 +14335,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2028,
-   "value": 36891.915260352755,
+   "value": 36772.53572338885,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11518,7 +14348,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2029,
-   "value": 37204.02706843331,
+   "value": 37156.5637359853,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11527,7 +14361,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2030,
-   "value": 37191.52316634799,
+   "value": 36685.78880542181,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11536,7 +14374,11 @@
   {
    "metric_id": "deciles.mean_income.3",
    "year": 2031,
-   "value": 37443.87462441918,
+   "value": 37377.12158903903,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11545,7 +14387,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2025,
-   "value": 37642.82250138588,
+   "value": 38934.091210418585,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11554,7 +14400,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2026,
-   "value": 39339.82023962752,
+   "value": 40539.44017480899,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11563,7 +14413,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2027,
-   "value": 40283.78733924495,
+   "value": 41468.195696983545,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11572,7 +14426,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2028,
-   "value": 41009.69588636075,
+   "value": 42373.92850208078,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11581,7 +14439,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2029,
-   "value": 41559.21709716546,
+   "value": 42841.52793419517,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11590,7 +14452,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2030,
-   "value": 42169.73199175639,
+   "value": 43336.4971038302,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11599,7 +14465,11 @@
   {
    "metric_id": "deciles.mean_income.4",
    "year": 2031,
-   "value": 43752.63830672907,
+   "value": 44285.75677905547,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11608,7 +14478,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2025,
-   "value": 45171.99281201596,
+   "value": 44653.353783363804,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11617,7 +14491,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2026,
-   "value": 46058.866814268324,
+   "value": 46131.613207371694,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11626,7 +14504,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2027,
-   "value": 46923.63741254213,
+   "value": 47073.502879079664,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11635,7 +14517,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2028,
-   "value": 47337.90189430204,
+   "value": 47372.95055950299,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11644,7 +14530,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2029,
-   "value": 48018.33585686029,
+   "value": 48085.54776182688,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11653,7 +14543,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2030,
-   "value": 48015.10342326575,
+   "value": 48110.89818838793,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11662,7 +14556,11 @@
   {
    "metric_id": "deciles.mean_income.5",
    "year": 2031,
-   "value": 49372.799605199805,
+   "value": 48857.4314782977,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11671,7 +14569,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2025,
-   "value": 48820.920957344184,
+   "value": 48283.828312490165,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11680,7 +14582,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2026,
-   "value": 50247.0931869786,
+   "value": 49405.72352548862,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11689,7 +14595,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2027,
-   "value": 51421.09655308313,
+   "value": 50162.973103580414,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11698,7 +14608,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2028,
-   "value": 52276.76979311605,
+   "value": 51093.240160099325,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11707,7 +14621,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2029,
-   "value": 52861.797979942385,
+   "value": 52375.72388322683,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11716,7 +14634,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2030,
-   "value": 54632.18051219701,
+   "value": 53906.52504776521,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11725,7 +14647,11 @@
   {
    "metric_id": "deciles.mean_income.6",
    "year": 2031,
-   "value": 56251.724813561,
+   "value": 55326.758982061125,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11734,7 +14660,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2025,
-   "value": 55387.77506364148,
+   "value": 54559.719261696424,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11743,7 +14673,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2026,
-   "value": 56756.00462516803,
+   "value": 55738.7030110715,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11752,7 +14686,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2027,
-   "value": 57200.40880691023,
+   "value": 56769.742467299,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11761,7 +14699,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2028,
-   "value": 58134.97463181802,
+   "value": 57552.98337993226,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11770,7 +14712,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2029,
-   "value": 58986.25591531483,
+   "value": 58018.55725963795,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11779,7 +14725,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2030,
-   "value": 60251.89005484455,
+   "value": 59147.87210110048,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11788,7 +14738,11 @@
   {
    "metric_id": "deciles.mean_income.7",
    "year": 2031,
-   "value": 62408.99721436145,
+   "value": 60637.60697260916,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11797,7 +14751,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2025,
-   "value": 70806.00916651895,
+   "value": 69236.41966938555,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11806,7 +14764,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2026,
-   "value": 72028.31133150091,
+   "value": 70232.37813773785,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11815,7 +14777,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2027,
-   "value": 73225.66554327721,
+   "value": 71531.33103123217,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11824,7 +14790,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2028,
-   "value": 74341.65681045009,
+   "value": 72791.02280987396,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11833,7 +14803,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2029,
-   "value": 75651.30440928646,
+   "value": 74106.60242542511,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11842,7 +14816,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2030,
-   "value": 76728.81669615183,
+   "value": 75628.31856190029,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11851,7 +14829,11 @@
   {
    "metric_id": "deciles.mean_income.8",
    "year": 2031,
-   "value": 77557.30506779443,
+   "value": 77611.71088167054,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11860,7 +14842,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2025,
-   "value": 78613.5574256512,
+   "value": 79276.26633204655,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11869,7 +14855,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2026,
-   "value": 80276.59014426098,
+   "value": 81581.90782711905,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11878,7 +14868,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2027,
-   "value": 81556.99374054834,
+   "value": 83106.87038322185,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11887,7 +14881,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2028,
-   "value": 83394.03807203949,
+   "value": 84575.49840158923,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11896,7 +14894,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2029,
-   "value": 84834.09750237051,
+   "value": 85864.95896332423,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11905,7 +14907,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2030,
-   "value": 86472.88055967825,
+   "value": 87649.69567899546,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11914,7 +14920,11 @@
   {
    "metric_id": "deciles.mean_income.9",
    "year": 2031,
-   "value": 90591.67357463166,
+   "value": 90654.08333059541,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11923,7 +14933,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2025,
-   "value": 121628.70831615487,
+   "value": 118030.04118236576,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11932,7 +14946,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2026,
-   "value": 124668.9979412319,
+   "value": 120826.03138084599,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11941,7 +14959,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2027,
-   "value": 125904.42260266874,
+   "value": 122592.51237304772,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11950,7 +14972,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2028,
-   "value": 128224.60518010141,
+   "value": 124339.6078872293,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11959,7 +14985,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2029,
-   "value": 130772.6528624675,
+   "value": 126219.29213328264,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11968,7 +14998,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2030,
-   "value": 133647.48170630506,
+   "value": 128486.66905357645,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11977,7 +15011,11 @@
   {
    "metric_id": "deciles.mean_income.10",
    "year": 2031,
-   "value": 135669.54991935962,
+   "value": 131631.3290311054,
+   "suppressed": false,
+   "excludes": [
+    "spending.disabled_students_allowance"
+   ],
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -11986,7 +15024,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2025,
-   "value": 6231978976.779907,
+   "value": 6222687308.254578,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -11995,7 +15035,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2026,
-   "value": 6514784443.9122925,
+   "value": 6508759614.741272,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12004,7 +15046,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2027,
-   "value": 6724056114.445618,
+   "value": 6714986157.079834,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12013,7 +15057,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2028,
-   "value": 6921661403.251404,
+   "value": 6913272334.154663,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12022,7 +15068,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2029,
-   "value": 7132082771.443726,
+   "value": 7118288039.173706,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12031,7 +15079,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2030,
-   "value": 7370366483.297607,
+   "value": 7356266082.489136,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12040,7 +15090,9 @@
   {
    "metric_id": "reforms.basic_rate_plus_1pp",
    "year": 2031,
-   "value": 7650165153.850464,
+   "value": 7633159472.480713,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12049,7 +15101,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2025,
-   "value": 6375058856.060486,
+   "value": 6366582048.682007,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12058,7 +15112,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2026,
-   "value": 6667124628.2039795,
+   "value": 6660786957.415405,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12067,7 +15123,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2027,
-   "value": 6885617422.428345,
+   "value": 6876392706.334412,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12076,7 +15134,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2028,
-   "value": 7091326778.457153,
+   "value": 7081815371.239807,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12085,7 +15145,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2029,
-   "value": 7306154419.062439,
+   "value": 7290951197.121887,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12094,7 +15156,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2030,
-   "value": 7546544692.554932,
+   "value": 7531692335.065491,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12103,7 +15167,9 @@
   {
    "metric_id": "reform_targets.basic_rate_plus_1pp",
    "year": 2031,
-   "value": 7822055582.338684,
+   "value": 7809724834.753845,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12112,7 +15178,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2025,
-   "value": 3666986552.897339,
+   "value": 3548582094.3916626,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12121,7 +15189,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2026,
-   "value": 3977030845.7789307,
+   "value": 3840615655.607727,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12130,7 +15200,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2027,
-   "value": 4223083637.6138306,
+   "value": 4076238853.5632935,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12139,7 +15211,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2028,
-   "value": 4369415244.928589,
+   "value": 4299497163.4904785,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12148,7 +15222,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2029,
-   "value": 4609416868.0217285,
+   "value": 4571859488.912842,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12157,7 +15233,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2030,
-   "value": 4888880522.356812,
+   "value": 4855874568.11499,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12166,7 +15244,9 @@
   {
    "metric_id": "reforms.higher_rate_plus_1pp",
    "year": 2031,
-   "value": 5111936398.052734,
+   "value": 5076062695.494751,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12175,7 +15255,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2025,
-   "value": 3671386650.1765137,
+   "value": 3554390535.588806,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12184,7 +15266,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2026,
-   "value": 3982920392.3969727,
+   "value": 3848232118.605835,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12193,7 +15277,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2027,
-   "value": 4229920079.0026245,
+   "value": 4084949832.10614,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12202,7 +15288,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2028,
-   "value": 4377131336.593445,
+   "value": 4309251584.078491,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12211,7 +15299,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2029,
-   "value": 4618077924.957153,
+   "value": 4582787139.6779785,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12220,7 +15310,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2030,
-   "value": 4898722761.492981,
+   "value": 4868223711.304871,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12229,7 +15321,9 @@
   {
    "metric_id": "reform_targets.higher_rate_plus_1pp",
    "year": 2031,
-   "value": 5122219947.487732,
+   "value": 5089139733.0060425,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12238,7 +15332,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2025,
-   "value": -3823707824.9178467,
+   "value": -3822246893.5978394,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12247,7 +15343,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2026,
-   "value": -3938856676.534912,
+   "value": -3970099818.8598022,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12256,7 +15354,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2027,
-   "value": -4026654105.0057983,
+   "value": -4052308604.757263,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12265,7 +15365,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2028,
-   "value": -4071413798.9171143,
+   "value": -4101725729.7006836,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12274,7 +15376,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2029,
-   "value": -4134957766.1256104,
+   "value": -4183390396.729248,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12283,7 +15387,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2030,
-   "value": -4229688107.533081,
+   "value": -4290067047.536621,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12292,7 +15398,9 @@
   {
    "metric_id": "reforms.personal_allowance_13000",
    "year": 2031,
-   "value": -1711397144.4260254,
+   "value": -2026458045.3624268,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12301,7 +15409,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2025,
-   "value": -3955109908.810852,
+   "value": -3954063036.4473877,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12310,7 +15420,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2026,
-   "value": -4086527957.4680176,
+   "value": -4117335693.9852905,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12319,7 +15431,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2027,
-   "value": -4183341947.9663086,
+   "value": -4209427536.251709,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12328,7 +15442,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2028,
-   "value": -4230614997.3900757,
+   "value": -4261098604.1522827,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12337,7 +15453,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2029,
-   "value": -4295011805.698914,
+   "value": -4343355439.515015,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12346,7 +15464,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2030,
-   "value": -4392504289.538818,
+   "value": -4452755767.392151,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12355,7 +15475,9 @@
   {
    "metric_id": "reform_targets.personal_allowance_13000",
    "year": 2031,
-   "value": -1765597207.2024536,
+   "value": -1780300034.5704956,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12364,7 +15486,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2025,
-   "value": -1977222467.3527832,
+   "value": -1978301080.5203857,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12373,7 +15497,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2026,
-   "value": -1744958365.3483887,
+   "value": -1746066703.213379,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12382,7 +15508,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2027,
-   "value": -1629814465.277588,
+   "value": -1629668073.130188,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12391,7 +15519,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2028,
-   "value": -1534763674.378479,
+   "value": -1530858259.5943604,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12400,7 +15530,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2029,
-   "value": -1428204556.7736816,
+   "value": -1428323970.4534912,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12409,7 +15541,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2030,
-   "value": -1322075255.131958,
+   "value": -1325576053.7683105,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12418,7 +15552,9 @@
   {
    "metric_id": "reforms.child_benefit_additional_25",
    "year": 2031,
-   "value": -1215395543.2149658,
+   "value": -1219354845.269043,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12427,7 +15563,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2025,
-   "value": 2332987565.3313274,
+   "value": 2330588637.038988,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12436,7 +15574,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2026,
-   "value": 2143319353.6422234,
+   "value": 2141486725.888443,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12445,7 +15585,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2027,
-   "value": 2025631616.9500465,
+   "value": 2023775956.2239304,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12454,7 +15596,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2028,
-   "value": 1921833405.853962,
+   "value": 1920161279.352703,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12463,7 +15607,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2029,
-   "value": 1815708316.6814766,
+   "value": 1813779891.1509056,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12472,7 +15618,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2030,
-   "value": 1706257920.2213326,
+   "value": 1704712527.6125221,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12481,7 +15629,9 @@
   {
    "metric_id": "reform_targets.child_benefit_additional_25",
    "year": 2031,
-   "value": 1592582974.3537292,
+   "value": 1591189257.2969856,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12490,7 +15640,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2025,
-   "value": -19987138619.665894,
+   "value": -20527842919.80768,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12499,7 +15651,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2026,
-   "value": -20585697292.380737,
+   "value": -21100518260.464355,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12508,7 +15662,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2027,
-   "value": -20867244208.72113,
+   "value": -21383710367.08246,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12517,7 +15673,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2028,
-   "value": -21212204041.55127,
+   "value": -21736411484.46698,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12526,7 +15684,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2029,
-   "value": -21266028636.272034,
+   "value": -21748894837.86438,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12535,7 +15695,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2030,
-   "value": -21323353884.143677,
+   "value": -21876938936.24524,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12544,7 +15706,9 @@
   {
    "metric_id": "reforms.uc_taper_20pc",
    "year": 2031,
-   "value": -21417216822.362915,
+   "value": -22330952654.634155,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12553,7 +15717,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2025,
-   "value": 20026032932.944794,
+   "value": 20519585447.911682,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12562,7 +15728,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2026,
-   "value": 20623599493.57924,
+   "value": 21090575767.801956,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12571,7 +15739,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2027,
-   "value": 20905978230.628372,
+   "value": 21373214076.36197,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12580,7 +15750,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2028,
-   "value": 21252138646.154373,
+   "value": 21725838011.858963,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12589,7 +15761,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2029,
-   "value": 21307648843.63382,
+   "value": 21742175658.693848,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12598,7 +15772,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2030,
-   "value": 21364495790.550797,
+   "value": 21868780192.75914,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12607,7 +15783,9 @@
   {
    "metric_id": "reform_targets.uc_taper_20pc",
    "year": 2031,
-   "value": 21460406654.06598,
+   "value": 22322933920.91278,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12616,7 +15794,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2025,
-   "value": 11191545342.31836,
+   "value": 11064401706.310059,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12625,7 +15805,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2026,
-   "value": 11645153494.695984,
+   "value": 11510324242.230225,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12634,7 +15816,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2027,
-   "value": 11972824309.717712,
+   "value": 11834108533.458801,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12643,7 +15827,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2028,
-   "value": 12257716047.155273,
+   "value": 12138956950.555908,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12652,7 +15838,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2029,
-   "value": 12566231791.670166,
+   "value": 12464179087.056396,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12661,7 +15849,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2030,
-   "value": 12912911611.737793,
+   "value": 12812306848.333618,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12670,7 +15860,9 @@
   {
    "metric_id": "reforms.employee_nics_main_10pc",
    "year": 2031,
-   "value": 13392154732.762207,
+   "value": 13289675311.854004,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12679,7 +15871,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2025,
-   "value": 11458770099.1045,
+   "value": 11329957618.034607,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12688,7 +15882,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2026,
-   "value": 11919342691.629387,
+   "value": 11791691034.516708,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12697,7 +15893,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2027,
-   "value": 12255153227.885277,
+   "value": 12126516761.37503,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12706,7 +15904,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2028,
-   "value": 12566120848.304436,
+   "value": 12442433003.455788,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12715,7 +15915,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2029,
-   "value": 12878237799.178757,
+   "value": 12770326792.025597,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12724,7 +15926,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2030,
-   "value": 13226533370.28511,
+   "value": 13120133297.630943,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12733,7 +15937,9 @@
   {
    "metric_id": "reform_targets.employee_nics_main_10pc",
    "year": 2031,
-   "value": 13713984420.560326,
+   "value": 13607405556.501923,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12742,7 +15948,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2025,
-   "value": 31259132637.84729,
+   "value": 30863021596.225952,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12751,7 +15959,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2026,
-   "value": 32099610265.377075,
+   "value": 31692844228.266296,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12760,7 +15970,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2027,
-   "value": 32862745005.17981,
+   "value": 32446311527.309143,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12769,7 +15981,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2028,
-   "value": 33654079646.918335,
+   "value": 33227617036.870483,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12778,7 +15992,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2029,
-   "value": 34478200723.7262,
+   "value": 34041293064.6344,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12787,7 +16003,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2030,
-   "value": 35326019624.22656,
+   "value": 34878374451.18152,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12796,7 +16014,9 @@
   {
    "metric_id": "reforms.vat_standard_plus_2pp",
    "year": 2031,
-   "value": 36187574723.726685,
+   "value": 35728921387.40991,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12805,7 +16025,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2025,
-   "value": 31259131903.187378,
+   "value": 30863018576.160828,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12814,7 +16036,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2026,
-   "value": 32099610338.78839,
+   "value": 31692847105.070984,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12823,7 +16047,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2027,
-   "value": 32862746112.62982,
+   "value": 32446312252.777954,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12832,7 +16058,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2028,
-   "value": 33654077425.53827,
+   "value": 33227616036.71393,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12841,7 +16069,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2029,
-   "value": 34478201429.00751,
+   "value": 34041297530.920654,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12850,7 +16080,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2030,
-   "value": 35326020466.349304,
+   "value": 34878372560.67273,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12859,7 +16091,9 @@
   {
    "metric_id": "reform_targets.vat_standard_plus_2pp",
    "year": 2031,
-   "value": 36187575185.13623,
+   "value": 35728918405.68787,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12868,7 +16102,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2025,
-   "value": 2825467413.079834,
+   "value": 2798505716.117798,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12877,7 +16113,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2026,
-   "value": 3049458999.274414,
+   "value": 3023336469.8702393,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12886,7 +16124,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2027,
-   "value": 3238599613.133667,
+   "value": 3213071953.8966064,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12895,7 +16135,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2028,
-   "value": 3549931915.0806885,
+   "value": 3394779601.3947754,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12904,7 +16146,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2029,
-   "value": 3756212324.8634033,
+   "value": 3594508773.6256104,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12913,7 +16157,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2030,
-   "value": 3997750150.373169,
+   "value": 3822543323.427368,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12922,7 +16168,9 @@
   {
    "metric_id": "reforms.additional_rate_plus_3pp",
    "year": 2031,
-   "value": 4332961887.065674,
+   "value": 4125743282.83667,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -12931,7 +16179,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2025,
-   "value": 2825466843.0894775,
+   "value": 2798504994.492798,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12940,7 +16190,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2026,
-   "value": 3049458483.8516235,
+   "value": 3023336460.849365,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12949,7 +16201,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2027,
-   "value": 3238600146.871582,
+   "value": 3213071862.152466,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12958,7 +16212,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2028,
-   "value": 3549931957.5039062,
+   "value": 3394780483.9908447,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12967,7 +16223,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2029,
-   "value": 3756211982.0652466,
+   "value": 3594509097.7042236,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12976,7 +16234,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2030,
-   "value": 3997750696.064453,
+   "value": 3822542242.9839478,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12985,7 +16245,9 @@
   {
    "metric_id": "reform_targets.additional_rate_plus_3pp",
    "year": 2031,
-   "value": 4332963129.139282,
+   "value": 4125743186.885071,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -12994,7 +16256,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2025,
-   "value": -3024426671.0059814,
+   "value": -3038583641.996826,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13003,7 +16267,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2026,
-   "value": -3159166047.906311,
+   "value": -3168138984.6657715,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13012,7 +16278,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2027,
-   "value": -3213933471.489624,
+   "value": -3225527730.8588867,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13021,7 +16289,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2028,
-   "value": -3272574045.103821,
+   "value": -3282105874.806885,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13030,7 +16300,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2029,
-   "value": -3304278267.8723145,
+   "value": -3307346412.4144287,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13039,7 +16311,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2030,
-   "value": -3329443110.629883,
+   "value": -3331520951.5113525,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13048,7 +16322,9 @@
   {
    "metric_id": "reforms.uc_standard_allowance_plus_10pc",
    "year": 2031,
-   "value": -3364831042.0513916,
+   "value": -3373553161.4073486,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13057,7 +16333,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2025,
-   "value": 3028001830.553894,
+   "value": 3041523709.2714844,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13066,7 +16344,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2026,
-   "value": 3162547160.014694,
+   "value": 3171636381.1340485,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13075,7 +16355,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2027,
-   "value": 3218303161.6876984,
+   "value": 3226364754.786072,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13084,7 +16366,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2028,
-   "value": 3277244745.4717865,
+   "value": 3282674243.09433,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13093,7 +16377,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2029,
-   "value": 3309693715.520218,
+   "value": 3312220329.68396,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13102,7 +16388,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2030,
-   "value": 3335295107.935898,
+   "value": 3337058613.859558,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13111,7 +16399,9 @@
   {
    "metric_id": "reform_targets.uc_standard_allowance_plus_10pc",
    "year": 2031,
-   "value": 3368860316.26828,
+   "value": 3377518834.7556,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13120,7 +16410,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2025,
-   "value": -9035141432.653503,
+   "value": -8927432756.88562,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13129,7 +16421,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2026,
-   "value": -9262484295.463745,
+   "value": -9142939686.93689,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13138,7 +16432,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2027,
-   "value": -9298804936.553955,
+   "value": -9062725924.750671,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13147,7 +16443,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2028,
-   "value": -9371209948.825623,
+   "value": -9114943836.081665,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13156,7 +16454,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2029,
-   "value": -9561709368.57013,
+   "value": -9306907164.58667,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13165,7 +16465,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2030,
-   "value": -9807065305.57251,
+   "value": -9548783655.451294,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13174,7 +16476,9 @@
   {
    "metric_id": "reforms.state_pension_plus_10pc",
    "year": 2031,
-   "value": -10306378596.512695,
+   "value": -9816145928.907349,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -13183,7 +16487,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2025,
-   "value": 12360890321.875732,
+   "value": 12250304093.31047,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13192,7 +16498,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2026,
-   "value": 12831378854.052383,
+   "value": 12711504064.702667,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13201,7 +16509,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2027,
-   "value": 13012698482.677444,
+   "value": 12828062954.26825,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13210,7 +16520,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2028,
-   "value": 13223877715.22789,
+   "value": 13020927023.28334,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13219,7 +16531,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2029,
-   "value": 13614122674.000916,
+   "value": 13405169512.460327,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13228,7 +16542,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2030,
-   "value": 14017293680.398499,
+   "value": 13802157356.131042,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13237,7 +16553,9 @@
   {
    "metric_id": "reform_targets.state_pension_plus_10pc",
    "year": 2031,
-   "value": 14429529140.882904,
+   "value": 14208043135.872528,
+   "suppressed": false,
+   "excludes": [],
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -13435,7 +16753,7 @@
     "2030",
     "2031"
    ],
-   "detail": "2025-26: 76 units below zero, a weighted \u00a3-69,996,281 in total; 2026-27: 76 units below zero, a weighted \u00a3-71,878,301 in total; 2027-28: 76 units below zero, a weighted \u00a3-73,587,136 in total; 2028-29: 76 units below zero, a weighted \u00a3-75,359,106 in total; 2029-30: 76 units below zero, a weighted \u00a3-77,204,504 in total; 2030-31: 76 units below zero, a weighted \u00a3-79,102,963 in total; 2031-32: 76 units below zero, a weighted \u00a3-81,032,183 in total"
+   "detail": "2025-26: 76 units below zero, a weighted \u00a3-67,632,237 in total; 2026-27: 76 units below zero, a weighted \u00a3-69,450,693 in total; 2027-28: 76 units below zero, a weighted \u00a3-71,101,816 in total; 2028-29: 76 units below zero, a weighted \u00a3-72,813,940 in total; 2029-30: 76 units below zero, a weighted \u00a3-74,597,010 in total; 2030-31: 76 units below zero, a weighted \u00a3-76,431,349 in total; 2031-32: 76 units below zero, a weighted \u00a3-78,295,212 in total"
   },
   {
    "identity_id": "inert:vat",
@@ -14625,6 +17943,38 @@
    "failing_scopes": [],
    "detail": ""
   },
+  {
+   "identity_id": "finite:statutory_paternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "failing_scopes": [],
+   "detail": ""
+  },
+  {
+   "identity_id": "sign:statutory_paternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "failing_scopes": [],
+   "detail": ""
+  },
+  {
+   "identity_id": "inert:statutory_paternity_pay",
+   "year": null,
+   "status": "warn",
+   "severity": "warn",
+   "failing_scopes": [
+    "2025",
+    "2026",
+    "2027",
+    "2028",
+    "2029",
+    "2030",
+    "2031"
+   ],
+   "detail": "2025-26: zero for every unit; 2026-27: zero for every unit; 2027-28: zero for every unit; 2028-29: zero for every unit; 2029-30: zero for every unit; 2030-31: zero for every unit; 2031-32: zero for every unit"
+  },
   {
    "identity_id": "finite:statutory_sick_pay",
    "year": null,
@@ -14948,10 +18298,10 @@
   {
    "identity_id": "sign:disabled_students_allowance",
    "year": null,
-   "status": "pass",
+   "status": "skipped",
    "severity": "fail",
    "failing_scopes": [],
-   "detail": ""
+   "detail": "2025-26: not checked, from fewer than 10 records; 2026-27: not checked, from fewer than 10 records; 2027-28: not checked, from fewer than 10 records; 2028-29: not checked, from fewer than 10 records; 2029-30: not checked, from fewer than 10 records; 2030-31: not checked, from fewer than 10 records; 2031-32: not checked, from fewer than 10 records"
   },
   {
    "identity_id": "inert:disabled_students_allowance",
@@ -15140,18 +18490,10 @@
   {
    "identity_id": "overlap_guard:property_transaction_tax_geography",
    "year": null,
-   "status": "fail",
+   "status": "pass",
    "severity": "fail",
-   "failing_scopes": [
-    "2025",
-    "2026",
-    "2027",
-    "2028",
-    "2029",
-    "2030",
-    "2031"
-   ],
-   "detail": "2025-26: 86 households have more than one, a weighted 39,273; 2026-27: 86 households have more than one, a weighted 39,422; 2027-28: 88 households have more than one, a weighted 39,718; 2028-29: 92 households have more than one, a weighted 40,335; 2029-30: 94 households have more than one, a weighted 40,724; 2030-31: 96 households have more than one, a weighted 41,410; 2031-32: 104 households have more than one, a weighted 42,213"
+   "failing_scopes": [],
+   "detail": ""
   },
   {
    "identity_id": "overlap_guard:local_tax_geography",
@@ -15740,22 +19082,26 @@
   {
    "identity_id": "counted_once:statutory_maternity_pay",
    "year": null,
-   "status": "fail",
+   "status": "pass",
    "severity": "fail",
-   "failing_scopes": [
-    ""
-   ],
-   "detail": "gov_spending: universal_credit rises by 0.0068 per unit of statutory_maternity_pay; household_benefits: universal_credit rises by 0.0068 per unit of statutory_maternity_pay"
+   "failing_scopes": [],
+   "detail": ""
+  },
+  {
+   "identity_id": "counted_once:statutory_paternity_pay",
+   "year": null,
+   "status": "pass",
+   "severity": "fail",
+   "failing_scopes": [],
+   "detail": ""
   },
   {
    "identity_id": "counted_once:statutory_sick_pay",
    "year": null,
-   "status": "fail",
+   "status": "pass",
    "severity": "fail",
-   "failing_scopes": [
-    ""
-   ],
-   "detail": "gov_spending: universal_credit rises by 0.0099 per unit of statutory_sick_pay; household_benefits: universal_credit rises by 0.0099 per unit of statutory_sick_pay"
+   "failing_scopes": [],
+   "detail": ""
   },
   {
    "identity_id": "counted_once:ssmg",

From 71a872df73abfd4a69c9edb137f7a7800e4dde1c Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 01:23:53 -0400
Subject: [PATCH 37/45] Read the metrics tool's small-cell format; pin it at
 228a05a3e

W3's aggregate-impact tool (policyengine-uk#2335, approved head
228a05a3e) publishes a figure from fewer than 10 records as value null,
suppressed true, and rebuilds every total that holds one without it,
listing it under excludes. The metrics review now:

- never compares a suppressed figure, and does not count it as
  non-finite; suppressed on both sides there is nothing to compare;
- withholds, for review, a figure suppressed on one side and any total
  whose sides exclude different figures, computing no change (it would
  give the small cell back). The report lists excluded ids without the
  sign each enters its total with, so differing exclusions are never
  lined up;
- fails a report with a suppressed value, a non-boolean flag, malformed
  excludes, or an excludes entry the same report does not suppress;
- treats a skipped check as not run: a skipped hard check, or one the
  previous pair ran, needs review.

The responsiveness gate cannot recompute the tool's verdict in a
withheld reform year, so a passing responsive check there needs review;
a failing one still fails.

The pin moves to 228a05a3e, whose standard reforms carry the minimums
adopted under cos d1344, and the fixtures follow. Rules agreed with W3.

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                      |   2 +-
 src/policyengine/data/qualification/uk.json   |   6 +-
 src/policyengine/provenance/uk_candidate.py   | 218 ++++++++-
 tests/fixtures/uk_metrics/README.md           |   9 +-
 .../fixtures/uk_metrics/standard_reforms.yaml |  78 ++-
 tests/test_uk_candidate_gates.py              | 449 +++++++++++++++++-
 6 files changed, 688 insertions(+), 74 deletions(-)

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index 73c9d238..b77718a6 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, and a skipped check counts as not run. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index 00281419..166823ba 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,9 +12,9 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "9b33fe19f80676fc5b81d2d80b36072e1c2fc1df",
+      "commit": "228a05a3e925beb50da619aa01e68c266e578fc0",
       "path": "policyengine_uk/utils/aggregate_impact",
-      "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions (draft policyengine-uk#2335). Move the pin to the merged commit when it lands."
+      "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions: the approved head of draft policyengine-uk#2335, the first that suppresses figures from fewer than 10 records. #2335 merges after cos d1601; move the pin to the merged commit when it lands, and never to a commit without suppression."
     },
     "years": [2025, 2026, 2027, 2028, 2029, 2030, 2031],
     "bounds": "uk_review_bounds.json"
@@ -30,7 +30,7 @@
     "poll_timeout_minutes": 360
   },
   "reform_responsiveness": {
-    "_comment": "Plan invariant 'Reform responsiveness' (11 Oct 2026): a reform the model silently ignores must fail qualification. The standard set, each reform's target variable, direction and yearly minimum are the metrics tool's own (standard_reforms.yaml in the pinned tool; the minimums are W3's proposals pending cos d1344). The tool costs the set by default and emits reform_runs: and responsive: checks. This gate requires both checks to be present and passing for every standard reform in the candidate's report, and recomputes each responsive verdict from the report's reform_targets. values.",
+    "_comment": "Plan invariant 'Reform responsiveness' (11 Oct 2026): a reform the model silently ignores must fail qualification. The standard set, each reform's target variable, direction and yearly minimum are the metrics tool's own (standard_reforms.yaml in the pinned tool; at 228a05a3e each minimum is a fifth of the reform's smallest yearly effect on the certified pair, adopted under cos d1344). The tool costs the set by default and emits reform_runs: and responsive: checks. This gate requires both checks to be present and passing for every standard reform in the candidate's report, and recomputes each responsive verdict from the report's reform_targets. values.",
     "standard_reforms_file": "standard_reforms.yaml"
   },
   "promotion": {
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 046ee1be..7b2abf68 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1330,6 +1330,65 @@ def classify_check(identity_id: str) -> str:
     return "hard"
 
 
+def _suppressed(row: Mapping[str, Any]) -> bool:
+    """Whether the tool published ``row`` as suppressed (fewer than 10 records)."""
+
+    return row.get("suppressed") is True
+
+
+def _excludes(row: Mapping[str, Any]) -> tuple[str, ...]:
+    """The suppressed figures a total is rebuilt without, in ``row``'s year."""
+
+    return tuple(sorted(str(metric_id) for metric_id in row.get("excludes") or ()))
+
+
+def _small_cell_problems(name: str, rows: Sequence[Mapping[str, Any]]) -> list[str]:
+    """Rows that break the tool's small-cell format, as problems.
+
+    The tool publishes a figure from fewer than 10 records with ``value``
+    null and ``suppressed`` true, and lists under ``excludes`` the suppressed
+    figures (by ``metric_id``) a total is rebuilt without that year
+    (``privacy.py`` and ``measure.rebuild_protected`` in the pinned tool). A
+    suppressed row with a value, a ``suppressed`` that is not a boolean, an
+    ``excludes`` that is not a list of ids, or an ``excludes`` entry naming a
+    figure the same report does not suppress in that year is a report this
+    gate cannot read safely.
+    """
+
+    hidden = {
+        (str(row.get("metric_id")), row.get("year")) for row in rows if _suppressed(row)
+    }
+    with_value, not_boolean, malformed, unmatched = [], [], [], []
+    for row in rows:
+        label = f"{row.get('metric_id')} {row.get('year')}"
+        flag = row.get("suppressed", False)
+        if not isinstance(flag, bool):
+            not_boolean.append(label)
+        elif flag and row.get("value") is not None:
+            with_value.append(label)
+        excludes = row.get("excludes", [])
+        if not isinstance(excludes, list) or not all(
+            isinstance(metric_id, str) for metric_id in excludes
+        ):
+            malformed.append(label)
+            continue
+        unmatched.extend(
+            f"{label} excludes {metric_id}"
+            for metric_id in excludes
+            if (metric_id, row.get("year")) not in hidden
+        )
+    problems = []
+    for found, what in (
+        (with_value, "suppressed figures with a value"),
+        (not_boolean, "a suppressed flag that is not true or false"),
+        (malformed, "excludes that are not a list of metric ids"),
+        (unmatched, "totals excluding a figure it does not suppress"),
+    ):
+        if found:
+            problems.append(f"the {name} report has {what}: {', '.join(found[:8])}")
+    return problems
+
+
 def _wider_failure(candidate: Mapping[str, Any], previous: Mapping[str, Any]) -> bool:
     """Whether a check failing in both reports fails in a scope it did not before.
 
@@ -1355,15 +1414,31 @@ def compare_metric_reports(
     checks fail outright; known-defect checks fail only when they worsen
     against the previous pair, meaning the previous pair did not fail them,
     or failed them in fewer scopes (``failing_scopes``, when the tool reports
-    them); ``warn`` is recorded, and a check that newly warns, or is skipped
-    where the previous pair passed it, needs review. ``skipped`` is neither a
-    pass nor a failure.
+    them); ``warn`` is recorded, and a check that newly warns needs review.
+    ``skipped`` means the check was not run, which is neither a pass nor a
+    failure: a skipped hard check, or a check skipped where the previous
+    pair ran it (pass, warn or fail), needs review.
 
     A report with a status other than ``ok``, no metrics or no checks fails,
     as does any check with a status outside ``CHECK_STATUSES``. A hard check
     the previous pair ran that is missing from the candidate fails (the two
     reports share one tool and one set of definitions); other missing checks
     need review.
+
+    Small cells (W3's tool publishes a figure from fewer than 10 records as
+    ``value`` null, ``suppressed`` true, and rebuilds every total that holds
+    one without it, listing it under ``excludes``):
+
+    - a suppressed figure is present but never compared, and is not a
+      non-finite value; suppressed on both sides, there is nothing to compare;
+    - a figure suppressed on one side only, or a total whose two sides leave
+      out different figures, is withheld: no change is computed (it would
+      give the suppressed figure back) and the comparison needs review. The
+      report lists the excluded ids without the sign each enters its total
+      with, so differing exclusions are never lined up here;
+    - a total compares numerically only when both sides exclude the same
+      figures;
+    - a report that breaks the format (``_small_cell_problems``) fails.
     """
 
     problems: list[str] = []
@@ -1385,7 +1460,9 @@ def compare_metric_reports(
     preexisting: list[str] = []
     new_warnings: list[str] = []
     warnings_: list[str] = []
+    skipped: list[str] = []
     newly_skipped: list[str] = []
+    hard_skipped: list[str] = []
     unknown_statuses: list[str] = []
     candidate_checks = set()
     for row in candidate.get("identities", []):
@@ -1409,8 +1486,13 @@ def compare_metric_reports(
             warnings_.append(check_id)
             if before == "pass":
                 new_warnings.append(check_id)
-        elif status == "skipped" and before == "pass":
-            newly_skipped.append(check_id)
+        elif status == "skipped":
+            # Not run: never a pass, whatever the check's class.
+            skipped.append(check_id)
+            if classify_check(check_id) == "hard":
+                hard_skipped.append(check_id)
+            if before in ("pass", "warn", "fail"):
+                newly_skipped.append(check_id)
     if unknown_statuses:
         # A status this gate does not know is not a pass.
         problems.append(
@@ -1439,9 +1521,10 @@ def compare_metric_reports(
         review.append(f"checks newly warn: {', '.join(new_warnings[:8])}")
     if newly_skipped:
         review.append(
-            "checks the previous pair passed were skipped: "
-            + ", ".join(newly_skipped[:8])
+            "checks the previous pair ran were not run: " + ", ".join(newly_skipped[:8])
         )
+    if hard_skipped:
+        review.append(f"hard checks were not run: {', '.join(hard_skipped[:8])}")
     if candidate.get("metrics_version") != previous.get("metrics_version"):
         problems.append(
             "metric definitions differ between the reports "
@@ -1467,17 +1550,23 @@ def compare_metric_reports(
                 f"the {name} report has duplicate metrics: "
                 + ", ".join(duplicate_metrics[:8])
             )
+        # A suppressed figure is published without a value by design.
         nonfinite = [
             f"{row.get('metric_id')} {row.get('year')}"
             for row in rows
-            if row.get("value") is None
-            or not isinstance(row.get("value"), (int, float))
-            or not math.isfinite(float(row["value"]))
+            if not _suppressed(row)
+            and (
+                row.get("value") is None
+                or isinstance(row.get("value"), bool)
+                or not isinstance(row.get("value"), (int, float))
+                or not math.isfinite(float(row["value"]))
+            )
         ]
         if nonfinite:
             problems.append(
                 f"the {name} report has non-finite values: {', '.join(nonfinite[:8])}"
             )
+        problems.extend(_small_cell_problems(name, rows))
     lost = sorted(f"{key[0]} {key[1]}" for key in set(before_metrics) - set(current))
     if lost:
         problems.append(f"metrics disappeared: {', '.join(lost[:8])}")
@@ -1487,12 +1576,42 @@ def compare_metric_reports(
     if without_baseline:
         review.append(f"metrics have no baseline: {', '.join(without_baseline[:8])}")
     moves = []
+    withheld: list[dict[str, Any]] = []
+    suppressed_on_both = 0
     for key, row in sorted(
         current.items(), key=lambda item: (item[0][0], item[0][1] or 0)
     ):
         old = before_metrics.get(key)
         if old is None:
             continue
+        if _suppressed(row) and _suppressed(old):
+            suppressed_on_both += 1
+            continue
+        if _suppressed(row) or _suppressed(old):
+            # A figure from fewer than 10 records on one side: so is its change.
+            withheld.append(
+                {
+                    "metric_id": key[0],
+                    "year": key[1],
+                    "reason": "suppressed in the "
+                    + ("candidate" if _suppressed(row) else "previous")
+                    + " report",
+                }
+            )
+            continue
+        if _excludes(row) != _excludes(old):
+            # Each side leaves out its own suppressed figures; their
+            # difference would mix definitions and could give one back.
+            withheld.append(
+                {
+                    "metric_id": key[0],
+                    "year": key[1],
+                    "reason": "the reports leave out different suppressed figures",
+                    "candidate_excludes": list(_excludes(row)),
+                    "previous_excludes": list(_excludes(old)),
+                }
+            )
+            continue
         try:
             new_value, old_value = float(row["value"]), float(old["value"])
         except (KeyError, TypeError, ValueError):
@@ -1516,6 +1635,12 @@ def compare_metric_reports(
             )
     if moves:
         review.append(f"{len(moves)} metric move(s) exceed their review bounds")
+    if withheld:
+        review.append(
+            f"{len(withheld)} metric change(s) are withheld because a figure "
+            "from fewer than 10 records is suppressed on one side, or the two "
+            "sides leave out different ones"
+        )
     evidence = {
         "metrics_version": candidate.get("metrics_version"),
         "partition_version": candidate.get("partition_version"),
@@ -1525,10 +1650,17 @@ def compare_metric_reports(
         "preexisting_check_failures": preexisting,
         "warn_identities": warnings_,
         "new_warnings": new_warnings,
+        "skipped_checks": skipped,
         "newly_skipped_checks": newly_skipped,
+        "hard_checks_not_run": hard_skipped,
         "unknown_status_checks": unknown_statuses,
         "lost_checks": lost_checks,
         "metrics_without_baseline": without_baseline,
+        "suppressed_metrics": sorted(
+            f"{key[0]} {key[1]}" for key, row in current.items() if _suppressed(row)
+        ),
+        "suppressed_on_both_sides": suppressed_on_both,
+        "withheld_changes": withheld,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
@@ -1537,12 +1669,14 @@ def compare_metric_reports(
         return "fail", "; ".join(problems), evidence
     if review:
         return "needs_review", "; ".join(review), evidence
-    note = (
-        f" ({len(preexisting)} known check failures carried over)"
-        if preexisting
-        else ""
-    )
-    return "pass", f"{len(current)} metrics within their review bounds{note}.", evidence
+    notes = []
+    if suppressed_on_both:
+        notes.append(f"{suppressed_on_both} suppressed on both sides, not compared")
+    if preexisting:
+        notes.append(f"{len(preexisting)} known check failures carried over")
+    note = f" ({'; '.join(notes)})" if notes else ""
+    compared = len(current) - suppressed_on_both
+    return "pass", f"{compared} metrics within their review bounds{note}.", evidence
 
 
 def metrics_review(
@@ -1622,10 +1756,15 @@ def reform_responsiveness(
       ``reform_targets.`` values, and a disagreement is an error
       (differential check of the check).
 
-    Any reform that does not respond fails the gate. There is no review
-    path: a reform the model silently ignores is a defect, never a small
-    number. The gate is monotone: shrinking a reform's response toward zero
-    or flipping its sign never turns a failure into a pass.
+    Any reform that does not respond fails the gate: a reform the model
+    silently ignores is a defect, never a small number. The one review path
+    is a year the tool withholds (``reform_targets.`` published as
+    suppressed, because the change would come from fewer than 10 records):
+    there the tool's verdict, which it takes from the withheld value, cannot
+    be recomputed, so a passing ``responsive`` check needs review rather
+    than passing; a failing one still fails. The gate is monotone: shrinking
+    a reform's response toward zero or flipping its sign never turns a
+    failure into a pass.
     """
 
     if unavailable_reason or report is None:
@@ -1645,12 +1784,13 @@ def reform_responsiveness(
     checks = {
         str(row.get("identity_id")): row for row in report.get("identities") or []
     }
-    values = {
-        (str(row.get("metric_id")), row.get("year")): row.get("value")
+    rows = {
+        (str(row.get("metric_id")), row.get("year")): row
         for row in report.get("metrics") or []
     }
     problems: list[str] = []
     disagreements: list[str] = []
+    unverifiable: list[str] = []
     table: list[dict[str, Any]] = []
     if report.get("status") not in (None, "ok"):
         problems.append(f"the report status is {report.get('status')!r}")
@@ -1662,10 +1802,17 @@ def reform_responsiveness(
         reform_id = reform["id"]
         sign = 1.0 if reform["direction"] == "up" else -1.0
         changes: dict[str, Any] = {}
-        recomputed = True
+        withheld_years: list[int] = []
+        # True: every year meets the minimum; False: a published year does
+        # not; None: every published year does, but a year is withheld.
+        recomputed: Optional[bool] = True
         for year in years:
-            value = values.get((f"reform_targets.{reform_id}", year))
+            target = rows.get((f"reform_targets.{reform_id}", year)) or {}
+            value = target.get("value")
             changes[str(year)] = value
+            if _suppressed(target) and value is None:
+                withheld_years.append(year)
+                continue
             if (
                 isinstance(value, bool)
                 or not isinstance(value, (int, float))
@@ -1673,11 +1820,14 @@ def reform_responsiveness(
                 or not sign * value >= reform["minimum"]
             ):
                 recomputed = False
+        if recomputed and withheld_years:
+            recomputed = None
         ran = (checks.get(f"reform_runs:{reform_id}") or {}).get("status")
         responsive = checks.get(f"responsive:{reform_id}") or {}
         row = {
             **reform,
             "target_changes": changes,
+            "withheld_years": withheld_years,
             "reform_runs": ran,
             "responsive": responsive.get("status"),
             "detail": responsive.get("detail"),
@@ -1692,7 +1842,18 @@ def reform_responsiveness(
                 + (responsive.get("detail") or "no responsive check in the report")
             )
         if ran == "pass" and responsive.get("status") in ("pass", "fail"):
-            if (responsive["status"] == "pass") != recomputed:
+            passed = responsive["status"] == "pass"
+            if recomputed is None:
+                # A failing verdict may come from a withheld year; a passing
+                # one cannot be checked there.
+                if passed:
+                    unverifiable.append(
+                        f"{label}: the tool's responsive check passes but "
+                        + ", ".join(_fiscal_year(year) for year in withheld_years)
+                        + " are withheld (fewer than 10 records), so it cannot "
+                        "be recomputed there"
+                    )
+            elif passed != recomputed:
                 disagreements.append(
                     f"{label}: the tool's responsive check is "
                     f"{responsive['status']} but its reform_targets values "
@@ -1714,6 +1875,13 @@ def reform_responsiveness(
         return _result(
             "reform_responsiveness", "error", "; ".join(disagreements[:6]), evidence
         )
+    if unverifiable:
+        return _result(
+            "reform_responsiveness",
+            "needs_review",
+            "; ".join(unverifiable[:6]),
+            evidence,
+        )
     return _result(
         "reform_responsiveness",
         "pass",
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index 3a26ba33..d45adc5a 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -16,10 +16,11 @@ the report; never edit them by hand.
   holds one is rebuilt without it and lists it under `excludes`. It has
   1,484 metric rows (14 suppressed: Disabled Students' Allowance's total and
   caseload in each of the seven years) and 350 checks.
-- `standard_reforms.yaml`: the tool's standard reform set, copied unchanged.
-  Ten reforms, each with the model variable it must move, the direction and
-  the least it must move it in every year. The reform responsiveness gate
-  reads the same file from the vendored tool.
+- `standard_reforms.yaml`: the tool's standard reform set at the same commit,
+  copied unchanged. Ten reforms, each with the model variable it must move,
+  the direction and the least it must move it in every year (a fifth of its
+  smallest yearly effect on the certified pair, adopted under cos d1344).
+  The reform responsiveness gate reads the same file from the vendored tool.
 
 This report replaces a 1.58.0 report from before the tool suppressed small
 cells. That report published Disabled Students' Allowance, which comes from
diff --git a/tests/fixtures/uk_metrics/standard_reforms.yaml b/tests/fixtures/uk_metrics/standard_reforms.yaml
index c2447136..402d8ae1 100644
--- a/tests/fixtures/uk_metrics/standard_reforms.yaml
+++ b/tests/fixtures/uk_metrics/standard_reforms.yaml
@@ -9,16 +9,50 @@
 # weighted total it must move, the direction, and the least it must move it
 # in every year of the horizon. A reform that moves its target by less, by
 # nothing or the wrong way fails the `responsive:` check, so a reform the
-# model silently ignores cannot pass as a small number. Each minimum is well
-# below the reform's smallest yearly effect on uk-data 1.58.0 in October 2026
-# (about a fifth of it for most), and is a proposal awaiting the
-# numerical-acceptance ruling (cos d1344). An absolute reform shrinks as the
-# baseline is uprated towards it: the 13,000 personal allowance is worth £4.4bn
-# in 2030-31 but £1.8bn in 2031-32, when the baseline allowance rises to
-# 12,830. From 2032-33 the baseline (13,090) exceeds it, so before the horizon
-# reaches that year, make that reform relative.
+# model silently ignores cannot pass as a small number.
+#
+# Calibration (adopted under cos d1344, 15 October 2026). Each minimum is a
+# fifth of the reform's smallest yearly effect over 2025-26 to 2031-32 on the
+# certified pair, rounded down to two significant figures; parse_reforms
+# refuses a minimum that does not follow from its smallest_effect. Recalibrate
+# with `python -m policyengine_uk.utils.aggregate_impact calibrate` on fresh
+# measurements, and change both numbers together.
+# - Pair: uk-data 1.58.1 (enhanced_frs_2024_25, sha256 056e80fd), measured
+#   with policyengine-uk 2.130.1 on policyengine-core 3.33.0 (the certified
+#   model, policyengine.py bundle uk-6.4.3) and with 2.132.6 on core 3.33.2.
+#   Every target change was identical between the two.
+# - What the check must catch: a PolicyEngine UK backtest (11 October 2026,
+#   cited in the Budget CI plan) found the 10% UC standard allowance rise
+#   returning exactly £0 from 2.45.1 to 2.75.3, and the 10% State Pension
+#   rise barely moving from 2.88.10 to 2.102.6.
+# - What it must not catch: legitimate moves. The fixture receipts show the
+#   2029-30 costings moving by up to 18% between data and model versions,
+#   and 38% for the VAT rise (21.2 on uk-data 1.40.3 against 34.5 on 1.58.0,
+#   from recorded consumption). A fifth fails a reform only once it has lost
+#   80% of its smallest yearly effect, twice the largest move seen.
+# - Alternatives considered: a tenth (fails only after a 90% loss, too late
+#   for "barely moving"); a half (the VAT data change kept 62% of the
+#   effect, so two such changes in a row would fail a correct model);
+#   per-year minimums (tighter in years where an absolute reform is worth
+#   more, but every horizon or data change would need a full table); an
+#   external anchor such as HMRC's ready reckoner (that tests calibration,
+#   not whether the reform is wired through); and a sign check alone
+#   (passes "barely moving").
+# - A single minimum is a wiring check, not a per-year 20% guarantee: the
+#   personal allowance minimum (£0.35bn) is 20% of its 2031-32 effect
+#   (£1.78bn) but 8% of its 2030-31 effect (£4.45bn), so a 90% loss in
+#   2030-31 alone would still pass.
+#
+# An absolute reform shrinks as the baseline is uprated towards it: the
+# 13,000 personal allowance is worth £4.45bn in 2030-31 but £1.78bn in
+# 2031-32, when the baseline allowance rises to 12,830. From 2032-33 the
+# baseline (13,090) exceeds it, so before the horizon reaches that year,
+# make that reform relative.
 schema_version: 1
 
+calibration:
+  fraction: 0.2
+
 reforms:
   - id: basic_rate_plus_1pp
     name: Raise basic rate by 1pp
@@ -27,7 +61,8 @@ reforms:
     responds:
       variable: income_tax
       direction: up
-      minimum: 1500000000
+      minimum: 1200000000
+      smallest_effect: 6366582049  # 2025-26
   - id: higher_rate_plus_1pp
     name: Raise higher rate by 1pp
     parameters:
@@ -35,7 +70,8 @@ reforms:
     responds:
       variable: income_tax
       direction: up
-      minimum: 1000000000
+      minimum: 710000000
+      smallest_effect: 3554390536  # 2025-26
   - id: personal_allowance_13000
     name: Raise personal allowance by ~800GBP/year
     parameters:
@@ -43,7 +79,8 @@ reforms:
     responds:
       variable: income_tax
       direction: down
-      minimum: 1000000000
+      minimum: 350000000
+      smallest_effect: 1780300035  # 2031-32
   - id: child_benefit_additional_25
     name: Raise child benefit by 25GBP/week per additional child
     parameters:
@@ -51,7 +88,8 @@ reforms:
     responds:
       variable: child_benefit
       direction: up
-      minimum: 300000000
+      minimum: 310000000
+      smallest_effect: 1591189257  # 2031-32
   - id: uc_taper_20pc
     name: Reduce Universal Credit taper rate to 20%
     parameters:
@@ -59,7 +97,8 @@ reforms:
     responds:
       variable: universal_credit
       direction: up
-      minimum: 4000000000
+      minimum: 4100000000
+      smallest_effect: 20519585448  # 2025-26
   - id: employee_nics_main_10pc
     name: Raise Class 1 main employee NICs rate to 10%
     parameters:
@@ -67,7 +106,8 @@ reforms:
     responds:
       variable: national_insurance
       direction: up
-      minimum: 2500000000
+      minimum: 2200000000
+      smallest_effect: 11329957618  # 2025-26
   - id: vat_standard_plus_2pp
     name: Raise VAT standard rate by 2pp
     parameters:
@@ -75,7 +115,8 @@ reforms:
     responds:
       variable: vat
       direction: up
-      minimum: 4000000000
+      minimum: 6100000000
+      smallest_effect: 30863018576  # 2025-26
   - id: additional_rate_plus_3pp
     name: Raise additional rate by 3pp
     parameters:
@@ -83,7 +124,8 @@ reforms:
     responds:
       variable: income_tax
       direction: up
-      minimum: 750000000
+      minimum: 550000000
+      smallest_effect: 2798504994  # 2025-26
   - id: uc_standard_allowance_plus_10pc
     name: Raise the Universal Credit standard allowance by 10%
     scale:
@@ -95,6 +137,7 @@ reforms:
       variable: universal_credit
       direction: up
       minimum: 600000000
+      smallest_effect: 3041523709  # 2025-26
   - id: state_pension_plus_10pc
     name: Raise the State Pension by 10%
     scale:
@@ -103,4 +146,5 @@ reforms:
     responds:
       variable: state_pension
       direction: up
-      minimum: 2500000000
+      minimum: 2400000000
+      smallest_effect: 12250304093  # 2025-26
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index ab0f7685..aafd090b 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1650,6 +1650,295 @@ def candidate(scale):
     assert order[smaller] <= order[full]
 
 
+DSA = "spending.disabled_students_allowance"
+
+
+def _cells(rows):
+    """A report from ``(metric_id, year, kind, value, suppressed, excludes)`` rows."""
+
+    report = _report({})
+    report["metrics"] = [
+        {
+            "metric_id": metric_id,
+            "year": year,
+            "kind": kind,
+            "value": value,
+            "suppressed": suppressed,
+            "excludes": list(excludes),
+        }
+        for metric_id, year, kind, value, suppressed, excludes in rows
+    ]
+    return report
+
+
+def _small_cell_pair(*, head=(None, True, ()), total=(5.4e11, False, (DSA,))):
+    """A suppressed head and a total rebuilt without it, for 2027."""
+
+    return _cells(
+        [
+            ("income_tax", 2027, "receipt", 3.0e11, False, ()),
+            (DSA, 2027, "spending", *head),
+            ("model.gov_spending", 2027, "model_total", *total),
+        ]
+    )
+
+
+def test_a_suppressed_figure_is_present_but_never_compared():
+    """W3's rule 1: a small cell is published as null, suppressed; not a NaN."""
+
+    status, summary, evidence = compare_metric_reports(
+        _small_cell_pair(), _small_cell_pair(), BOUNDS
+    )
+    assert status == "pass", summary
+    assert evidence["suppressed_metrics"] == [f"{DSA} 2027"]
+    assert evidence["suppressed_on_both_sides"] == 1
+    assert "2 metrics within their review bounds" in summary
+    # A null that is not marked suppressed is still a non-finite value.
+    unmarked = _small_cell_pair(head=(None, False, ()))
+    status, summary, _ = compare_metric_reports(unmarked, _small_cell_pair(), BOUNDS)
+    assert status == "fail" and f"non-finite values: {DSA} 2027" in summary
+
+
+@pytest.mark.parametrize(
+    ("candidate", "previous", "reason"),
+    [
+        (
+            _small_cell_pair(),
+            _small_cell_pair(head=(2.0e6, False, ()), total=(5.4e11, False, ())),
+            "suppressed in the candidate report",
+        ),
+        (
+            _small_cell_pair(head=(2.0e6, False, ()), total=(5.4e11, False, ())),
+            _small_cell_pair(),
+            "suppressed in the previous report",
+        ),
+    ],
+    ids=["newly suppressed", "no longer suppressed"],
+)
+def test_a_figure_suppressed_on_one_side_is_withheld(candidate, previous, reason):
+    """Its change would come from fewer than 10 records: never computed."""
+
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "needs_review", summary
+    assert "withheld" in summary
+    withheld = {
+        (row["metric_id"], row["reason"]) for row in evidence["withheld_changes"]
+    }
+    assert (DSA, reason) in withheld
+    # The total's sides leave out different figures, so it is withheld too,
+    # even though its two published values are equal.
+    assert (
+        "model.gov_spending",
+        "the reports leave out different suppressed figures",
+    ) in withheld
+    assert evidence["moves_beyond_bounds"] == []
+
+
+@pytest.mark.parametrize(
+    "kind", ["model_total", "balance", "decile", "household_total"]
+)
+@pytest.mark.parametrize("candidate_value", [5.4e11, 5.4e11 + 1.0, 9.9e11])
+def test_totals_with_different_exclusions_are_never_lined_up(kind, candidate_value):
+    """The report lists excluded ids without their signs, so no section,
+    additive or not, gets a computed change: it is withheld for review."""
+
+    def side(value, excludes):
+        return _cells(
+            [
+                ("income_tax", 2027, "receipt", 3.0e11, False, ()),
+                (DSA, 2027, "spending", None, True, ()),
+                ("other_head", 2027, "spending", None, True, ()),
+                ("total", 2027, kind, value, False, excludes),
+            ]
+        )
+
+    candidate = side(candidate_value, (DSA, "other_head"))
+    previous = side(5.4e11, (DSA,))
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "needs_review", summary
+    (row,) = evidence["withheld_changes"]
+    assert row == {
+        "metric_id": "total",
+        "year": 2027,
+        "reason": "the reports leave out different suppressed figures",
+        "candidate_excludes": sorted([DSA, "other_head"]),
+        "previous_excludes": [DSA],
+    }
+    assert evidence["moves_beyond_bounds"] == []
+
+
+def test_totals_at_equal_exclusions_compare_numerically():
+    small = _small_cell_pair(total=(5.4e11 + 1.0e9, False, (DSA,)))
+    assert compare_metric_reports(small, _small_cell_pair(), BOUNDS)[0] == "pass"
+    large = _small_cell_pair(total=(6.0e11, False, (DSA,)))
+    status, _, evidence = compare_metric_reports(large, _small_cell_pair(), BOUNDS)
+    assert status == "needs_review"
+    assert [move["metric_id"] for move in evidence["moves_beyond_bounds"]] == [
+        "model.gov_spending"
+    ]
+    assert evidence["withheld_changes"] == []
+
+
+@pytest.mark.parametrize(
+    ("mutate", "message"),
+    [
+        (
+            lambda rows: rows[1].update(value=2.0e6),
+            f"suppressed figures with a value: {DSA} 2027",
+        ),
+        (
+            lambda rows: rows[1].update(suppressed="yes"),
+            "a suppressed flag that is not true or false",
+        ),
+        (
+            lambda rows: rows[2].update(excludes=DSA),
+            "excludes that are not a list of metric ids",
+        ),
+        (
+            lambda rows: rows[2].update(excludes=[DSA, 7]),
+            "excludes that are not a list of metric ids",
+        ),
+        (
+            lambda rows: rows[2].update(excludes=[DSA, "income_tax"]),
+            "totals excluding a figure it does not suppress: "
+            "model.gov_spending 2027 excludes income_tax",
+        ),
+        (
+            lambda rows: rows[2].update(year=2028),
+            "totals excluding a figure it does not suppress",
+        ),
+    ],
+    ids=[
+        "suppressed with a value",
+        "flag not boolean",
+        "excludes a string",
+        "excludes a number",
+        "excludes an unsuppressed figure",
+        "excludes a figure suppressed in another year",
+    ],
+)
+@pytest.mark.parametrize("side", ["candidate", "previous"])
+def test_a_report_that_breaks_the_small_cell_format_fails(mutate, message, side):
+    broken = _small_cell_pair()
+    mutate(broken["metrics"])
+    pair = (broken, _small_cell_pair())
+    if side == "previous":
+        pair = pair[::-1]
+    status, summary, _ = compare_metric_reports(*pair, BOUNDS)
+    assert status == "fail", summary
+    assert f"the {side} report has" in summary and message in summary
+
+
+def test_a_boolean_metric_value_is_not_a_number():
+    report = _report(BASE)
+    report["metrics"][0]["value"] = True
+    status, summary, _ = compare_metric_reports(report, _report(BASE), BOUNDS)
+    assert status == "fail" and "non-finite values" in summary
+
+
+@pytest.mark.parametrize(
+    ("check", "previous", "status", "newly", "hard"),
+    [
+        # W3's rule 4: skipped means not run.
+        ("sign:dsa", "skipped", "pass", False, False),
+        ("sign:dsa", None, "pass", False, False),
+        ("sign:dsa", "pass", "needs_review", True, False),
+        ("sign:dsa", "warn", "needs_review", True, False),
+        # A known failure that is no longer run is not a fix.
+        ("sign:dsa", "fail", "needs_review", True, False),
+        # A hard check that was not run is never a pass.
+        ("closure", "skipped", "needs_review", False, True),
+        ("finite:metrics", None, "needs_review", False, True),
+        ("responsive:x", "pass", "needs_review", True, True),
+    ],
+)
+def test_a_skipped_check_is_not_run(check, previous, status, newly, hard):
+    before = [] if previous is None else [{"identity_id": check, "status": previous}]
+    result = compare_metric_reports(
+        _report(BASE, identities=[{"identity_id": check, "status": "skipped"}]),
+        _report(BASE, identities=before),
+        BOUNDS,
+    )
+    assert result[0] == status, result[1]
+    evidence = result[2]
+    assert evidence["skipped_checks"] == [check]
+    assert evidence["newly_skipped_checks"] == ([check] if newly else [])
+    assert evidence["hard_checks_not_run"] == ([check] if hard else [])
+
+
+_CELL = st.tuples(
+    st.sampled_from(["published", "suppressed"]),
+    st.sampled_from([(), (DSA,), (DSA, "other_head")]),
+    st.floats(min_value=-0.5, max_value=0.5, allow_nan=False),
+)
+
+
+@settings(max_examples=300, deadline=None)
+@given(cells=st.lists(st.tuples(_CELL, _CELL), min_size=1, max_size=4))
+def test_the_small_cell_rule_against_a_reference(cells):
+    """Differential: the gate's status for small cells matches the rule
+    stated independently, and no withheld change carries a value."""
+
+    def side(choices):
+        rows = [
+            (DSA, 2027, "spending", None, True, ()),
+            ("other_head", 2027, "spending", None, True, ()),
+        ]
+        for i, (state, excludes, change) in enumerate(choices):
+            value = None if state == "suppressed" else 1.0e11 * (1 + change)
+            rows.append(
+                (f"m{i}", 2027, "model_total", value, state == "suppressed", excludes)
+            )
+        return _cells(rows)
+
+    candidate = side([pair[0] for pair in cells])
+    previous = side([pair[1] for pair in cells])
+    expected = "pass"
+    for (state_c, ex_c, ch_c), (state_p, ex_p, ch_p) in cells:
+        if state_c == state_p == "suppressed":
+            continue
+        if "suppressed" in (state_c, state_p) or tuple(sorted(ex_c)) != tuple(
+            sorted(ex_p)
+        ):
+            expected = "needs_review"
+            continue
+        new, old = 1.0e11 * (1 + ch_c), 1.0e11 * (1 + ch_p)
+        if abs(new - old) > max(0.02 * abs(old), 5e8):
+            expected = "needs_review"
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == expected, summary
+    for row in evidence["withheld_changes"]:
+        assert set(row) <= {
+            "metric_id",
+            "year",
+            "reason",
+            "candidate_excludes",
+            "previous_excludes",
+        }
+
+
+@settings(max_examples=200, deadline=None)
+@given(
+    rows=st.lists(
+        st.tuples(
+            st.sampled_from(["income_tax", "vat", DSA]),
+            st.sampled_from([2026, 2027]),
+            st.one_of(st.none(), st.floats(allow_nan=True, allow_infinity=True)),
+            st.sampled_from([True, False]),
+            st.sampled_from([(), (DSA,)]),
+        ),
+        min_size=1,
+        max_size=6,
+    )
+)
+def test_a_suppressed_cell_never_hides_a_hard_failure(rows):
+    """Whatever the cells, a failed hard check still fails the comparison."""
+
+    report = _cells([(m, y, "receipt", v, s, e) for m, y, v, s, e in rows])
+    report["identities"] = [{"identity_id": "closure", "status": "fail"}]
+    assert compare_metric_reports(report, report, BOUNDS)[0] == "fail"
+
+
 def test_metrics_gate_splits_model_and_data_steps():
     cross = {**BASE, ("income_tax", 2027, "receipt"): 3.2e11}
     result, evidence = metrics_review(
@@ -2110,7 +2399,7 @@ def test_the_standard_reforms_are_read_from_the_vendored_tool(tmp_path):
         "name": "Raise basic rate by 1pp",
         "variable": "income_tax",
         "direction": "up",
-        "minimum": 1.5e9,
+        "minimum": 1.2e9,
     }
     assert {reform["id"] for reform in reforms} >= {
         "uc_standard_allowance_plus_10pc",
@@ -2377,6 +2666,78 @@ def test_responsiveness_is_monotone_in_the_size_of_the_response(low, high):
     assert (stronger == "pass") == (high >= 1.0)
 
 
+def _withhold(report, reform_id, years):
+    """Publish ``reform_id``'s target change as suppressed in ``years``, as
+    the tool does for a change from fewer than 10 records."""
+
+    for row in report["metrics"]:
+        if row["metric_id"] == f"reform_targets.{reform_id}" and row["year"] in years:
+            row.update(value=None, suppressed=True)
+    return report
+
+
+def test_a_withheld_year_cannot_pass_unverified():
+    """W3's rule 5: the tool decides responsiveness from the withheld value;
+    the gate cannot recompute it, so a pass there needs review."""
+
+    report = _withhold(_responsive_report(), UC_ALLOWANCE, {2027})
+    result, evidence = reform_responsiveness_gate(report)
+    assert result.status == "needs_review", result.summary
+    assert f"({UC_ALLOWANCE})" in result.summary and "2027-28" in result.summary
+    rows = {row["id"]: row for row in evidence["reforms"]}
+    assert rows[UC_ALLOWANCE]["withheld_years"] == [2027]
+    assert rows[UC_ALLOWANCE]["target_changes"]["2027"] is None
+    # Withholding every year is no better.
+    everything = _withhold(_responsive_report(), UC_ALLOWANCE, set(RESPONSE_YEARS))
+    assert reform_responsiveness_gate(everything)[0].status == "needs_review"
+
+
+def test_a_withheld_year_never_excuses_a_failure():
+    # The tool's failing verdict may come from the withheld year: it fails.
+    failing = _withhold(_responsive_report(), UC_ALLOWANCE, {2027})
+    for row in failing["identities"]:
+        if row["identity_id"] == f"responsive:{UC_ALLOWANCE}":
+            row.update(status="fail", detail="2027-28: did not move enough")
+    result = reform_responsiveness_gate(failing)[0]
+    assert (
+        result.status == "fail"
+        and f"({UC_ALLOWANCE}) did not respond" in result.summary
+    )
+    # A published year that misses the minimum, under a passing verdict, is
+    # still a disagreement, withheld years or not.
+    lying = _withhold(
+        _responsive_report(overrides={(UC_ALLOWANCE, 2028): 0.0}, lie=UC_ALLOWANCE),
+        UC_ALLOWANCE,
+        {2027},
+    )
+    assert reform_responsiveness_gate(lying)[0].status == "error"
+    # A null that is not marked suppressed is a missing value, not withheld.
+    unmarked = _responsive_report()
+    for row in unmarked["metrics"]:
+        if row["metric_id"] == f"reform_targets.{UC_ALLOWANCE}" and row["year"] == 2027:
+            row["value"] = None
+    assert reform_responsiveness_gate(unmarked)[0].status == "error"
+
+
+@settings(max_examples=100, deadline=None)
+@given(
+    withheld=st.sets(st.sampled_from(RESPONSE_YEARS)),
+    scale=st.floats(min_value=-3.0, max_value=6.0),
+)
+def test_withholding_never_improves_responsiveness(withheld, scale):
+    """Monotone in information: withholding years never turns a fail or an
+    error into a pass, and never passes at all."""
+
+    order = {"pass": 0, "needs_review": 1, "fail": 2, "error": 2}
+    full = reform_responsiveness_gate(_responsive_report(scale=scale))[0].status
+    hidden = reform_responsiveness_gate(
+        _withhold(_responsive_report(scale=scale), STATE_PENSION, withheld)
+    )[0].status
+    if withheld:
+        assert hidden != "pass"
+    assert order[hidden] >= order[full]
+
+
 REAL_REPORT = (
     Path(__file__).parent / "fixtures" / "uk_metrics" / "budget_metrics_report.json"
 )
@@ -2397,7 +2758,8 @@ def test_the_real_report_on_the_certified_data_passes_responsiveness():
     uc = rows["uc_standard_allowance_plus_10pc"]["target_changes"]
     pension = rows["state_pension_plus_10pc"]["target_changes"]
     assert all(3.0e9 < value < 3.4e9 for value in uc.values())
-    assert all(12.3e9 < value < 14.5e9 for value in pension.values())
+    assert all(12.0e9 < value < 14.5e9 for value in pension.values())
+    assert all(row["withheld_years"] == [] for row in rows.values())
 
 
 def reform_responsiveness_gate(report):
@@ -2427,33 +2789,38 @@ def test_the_backtest_failures_fail_on_the_real_report(reform_id):
     assert f"({reform_id}) did not respond" in result.summary
 
 
-def test_the_real_report_fits_the_metrics_review_classification():
-    """Every check that fails on main is a no-worsening check, and every
-    metric kind has a review bound, so a pair compared with itself passes."""
-
-    from policyengine.provenance.uk_candidate import classify_check
-
-    report = _real_report()
-    bounds = json.loads(
+def _real_bounds():
+    return json.loads(
         (
             Path(__file__).parents[1]
             / "src/policyengine/data/qualification/uk_review_bounds.json"
         ).read_text()
     )
+
+
+def test_the_real_report_fits_the_metrics_review_classification():
+    """Every check that fails on the certified pair is a no-worsening check,
+    and every metric kind has a review bound, so a pair compared with itself
+    passes, suppressed figures and all."""
+
+    from policyengine.provenance.uk_candidate import classify_check
+
+    report = _real_report()
+    bounds = _real_bounds()
     failing = sorted(
         row["identity_id"] for row in report["identities"] if row["status"] == "fail"
     )
-    assert failing == [
-        "counted_once:statutory_maternity_pay",
-        "counted_once:statutory_sick_pay",
-        "overlap_guard:property_transaction_tax_geography",
-        "sign:vat",
-    ]
+    assert failing == ["sign:vat"]
     assert {classify_check(check_id) for check_id in failing} == {"regression"}
     assert {row["kind"] for row in report["metrics"]} <= set(bounds["kinds"])
     status, summary, evidence = compare_metric_reports(report, report, bounds)
     assert status == "pass", summary
+    assert "14 suppressed on both sides, not compared" in summary
     assert sorted(evidence["preexisting_check_failures"]) == failing
+    assert evidence["skipped_checks"] == ["sign:disabled_students_allowance"]
+    assert evidence["newly_skipped_checks"] == evidence["hard_checks_not_run"] == []
+    assert evidence["withheld_changes"] == []
+    assert len(evidence["suppressed_metrics"]) == 14
     # The same failures against a pair that passed them are regressions.
     clean = _real_report()
     for row in clean["identities"]:
@@ -2462,23 +2829,57 @@ def test_the_real_report_fits_the_metrics_review_classification():
     assert compare_metric_reports(report, clean, bounds)[0] == "fail"
 
 
+def test_the_real_report_suppresses_its_small_cells():
+    """W3's report on the certified pair: Disabled Students' Allowance comes
+    from fewer than 10 records, so its total and caseload are suppressed in
+    every year, every total holding it is rebuilt without it, and its sign
+    check is not run. A report that published it would fail the gate."""
+
+    report = _real_report()
+    suppressed = sorted(
+        (row["metric_id"], row["year"])
+        for row in report["metrics"]
+        if row["suppressed"]
+    )
+    dsa = (
+        "spending.disabled_students_allowance",
+        "caseloads.disabled_students_allowance",
+    )
+    assert suppressed == sorted((m, y) for m in dsa for y in RESPONSE_YEARS)
+    assert all(row["value"] is None for row in report["metrics"] if row["suppressed"])
+    rebuilt = [row for row in report["metrics"] if row["excludes"]]
+    assert len(rebuilt) == 112
+    assert len({row["metric_id"] for row in rebuilt}) == 16
+    assert {tuple(row["excludes"]) for row in rebuilt} == {(dsa[0],)}
+    # A figure published from a small cell, or a total that names one it
+    # does not suppress, is a report the gate cannot read safely.
+    published = _real_report()
+    for row in published["metrics"]:
+        if row["metric_id"] == dsa[0] and row["year"] == 2027:
+            row["value"] = 1.0e6
+    status, summary, _ = compare_metric_reports(published, report, _real_bounds())
+    assert status == "fail"
+    assert f"suppressed figures with a value: {dsa[0]} 2027" in summary
+    unsuppressed = _real_report()
+    for row in unsuppressed["metrics"]:
+        if row["metric_id"] == dsa[0] and row["year"] == 2027:
+            row.update(value=1.0e6, suppressed=False)
+    status, summary, _ = compare_metric_reports(unsuppressed, report, _real_bounds())
+    assert status == "fail"
+    assert "totals excluding a figure it does not suppress" in summary
+
+
 def test_a_real_failure_that_spread_to_a_new_year_has_worsened():
     """Scope-based no-worsening on the tool's real failing_scopes."""
 
-    bounds = json.loads(
-        (
-            Path(__file__).parents[1]
-            / "src/policyengine/data/qualification/uk_review_bounds.json"
-        ).read_text()
-    )
+    bounds = _real_bounds()
     report = _real_report()
     scopes = {
         row["identity_id"]: row["failing_scopes"]
         for row in report["identities"]
         if row["status"] == "fail"
     }
-    assert scopes["sign:vat"] == [str(year) for year in RESPONSE_YEARS]
-    assert scopes["counted_once:statutory_sick_pay"] == [""]
+    assert scopes == {"sign:vat": [str(year) for year in RESPONSE_YEARS]}
     # The previous pair failed sign:vat in every year but the last.
     earlier = _real_report()
     for row in earlier["identities"]:

From 3fa3d74cf0c446e222713bcfe0e5edb0ed9b7930 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 01:59:51 -0400
Subject: [PATCH 38/45] Line up additive totals with exclude_signs; close
 supp-r1's findings

Pin the metrics tool at 1191ac5a4 (policyengine-uk#2335's approved
head), whose report gives each excluded figure's sign in exclude_signs,
and refresh the fixture (values, suppression and checks unchanged).

- An additive total (model_totals, balance, household net income: the
  tool's compare._additive) whose sides exclude different figures is
  lined up as compare._aligned does: each side takes out, at its own
  published value and the excluding side's sign, every figure only the
  other side excludes. The relative bound stays on the previous
  published total, as the tool's flag threshold is. Other totals, or
  ones that cannot be lined up (a needed figure not published, a shared
  figure with different signs, invalid signs), are withheld for review.
- The format check now requires the small-cell fields (a report from a
  tool before suppression fails), integer years, exclude_signs of +1 or
  -1 for exactly the excluded figures, and a caseload suppressed
  together with its spending head.
- supp-r1 P1: a suppressed reform target is never copied into evidence;
  one carrying a value is an error. Only reports in the small-cell
  format are written to the public ledger; any other is kept as its
  digest and problems.
- supp-r1 P2s: a report that repeats a check fails, an unknown status in
  the previous report fails, repeated reform rows are an error, and any
  warning the previous report did not give is new (the tool's
  new_warning).
- Tests: lining up against an independent reference (Hypothesis), the
  bound denominator, the real report with a synthetic previous head,
  the boolean-target mutant, and a responsiveness property whose
  generator varies one reform.

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                      |    2 +-
 src/policyengine/data/qualification/uk.json   |    4 +-
 src/policyengine/provenance/uk_candidate.py   |  366 +++-
 tests/fixtures/uk_metrics/README.md           |   15 +-
 .../uk_metrics/budget_metrics_report.json     | 1710 ++++++++++++++++-
 tests/test_uk_candidate_gates.py              |  544 +++++-
 tests/test_uk_candidate_metric_baselines.py   |   68 +-
 7 files changed, 2572 insertions(+), 137 deletions(-)

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index b77718a6..7aa73eb5 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, and a skipped check counts as not run. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/src/policyengine/data/qualification/uk.json b/src/policyengine/data/qualification/uk.json
index 166823ba..d50e0eba 100644
--- a/src/policyengine/data/qualification/uk.json
+++ b/src/policyengine/data/qualification/uk.json
@@ -12,9 +12,9 @@
   "metrics": {
     "tool": {
       "repository": "PolicyEngine/policyengine-uk",
-      "commit": "228a05a3e925beb50da619aa01e68c266e578fc0",
+      "commit": "1191ac5a473419f48e0c0643f83d31719da788e1",
       "path": "policyengine_uk/utils/aggregate_impact",
-      "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions: the approved head of draft policyengine-uk#2335, the first that suppresses figures from fewer than 10 records. #2335 merges after cos d1601; move the pin to the merged commit when it lands, and never to a commit without suppression."
+      "_comment": "W3's aggregate-impact tool, pinned so both pairs use the same definitions: the approved head of draft policyengine-uk#2335. It suppresses figures from fewer than 10 records and gives each total's excluded figures with their signs (exclude_signs), which the metrics review requires. #2335 merges after cos d1601; move the pin to the merged commit when it lands, and never to a commit without suppression."
     },
     "years": [2025, 2026, 2027, 2028, 2029, 2030, 2031],
     "bounds": "uk_review_bounds.json"
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 7b2abf68..e8acc9de 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1342,53 +1342,154 @@ def _excludes(row: Mapping[str, Any]) -> tuple[str, ...]:
     return tuple(sorted(str(metric_id) for metric_id in row.get("excludes") or ()))
 
 
+#: The fields the pinned tool gives every metric row under its small-cell
+#: rule (``api.to_report`` at policyengine-uk 1191ac5a4). A report without
+#: them comes from a tool that predates suppression and may publish a figure
+#: from fewer than 10 records, so it fails.
+SMALL_CELL_FIELDS = ("suppressed", "excludes", "exclude_signs")
+
+
+def _finite_number(value: Any) -> bool:
+    return (
+        not isinstance(value, bool)
+        and isinstance(value, (int, float))
+        and math.isfinite(value)
+    )
+
+
+def _valid_signs(row: Mapping[str, Any]) -> Optional[dict[str, int]]:
+    """``exclude_signs`` when it gives +1 or -1 for exactly the excluded ids."""
+
+    signs, excludes = row.get("exclude_signs"), row.get("excludes")
+    if not isinstance(signs, Mapping) or not isinstance(excludes, list):
+        return None
+    if set(signs) != set(excludes) or not all(
+        not isinstance(sign, bool) and sign in (1, -1) for sign in signs.values()
+    ):
+        return None
+    return {str(metric_id): int(sign) for metric_id, sign in signs.items()}
+
+
 def _small_cell_problems(name: str, rows: Sequence[Mapping[str, Any]]) -> list[str]:
     """Rows that break the tool's small-cell format, as problems.
 
     The tool publishes a figure from fewer than 10 records with ``value``
-    null and ``suppressed`` true, and lists under ``excludes`` the suppressed
-    figures (by ``metric_id``) a total is rebuilt without that year
-    (``privacy.py`` and ``measure.rebuild_protected`` in the pinned tool). A
-    suppressed row with a value, a ``suppressed`` that is not a boolean, an
-    ``excludes`` that is not a list of ids, or an ``excludes`` entry naming a
-    figure the same report does not suppress in that year is a report this
-    gate cannot read safely.
+    null and ``suppressed`` true. A spending head's caseload is suppressed
+    with it, from the same records. Every total holding a suppressed figure
+    is rebuilt without it; the total lists the figure's ``metric_id`` under
+    ``excludes`` and the sign it enters with, +1 or -1, under
+    ``exclude_signs`` (``privacy.py``, ``measure.measure_year`` and
+    ``measure.rebuild_protected`` in the pinned tool). These are reports this
+    gate cannot read safely:
+
+    - a row without the small-cell fields, or whose year is not an integer;
+    - a suppressed row with a value, or a ``suppressed`` that is not a
+      boolean;
+    - an ``excludes`` that is not a list of ids, or names a figure the same
+      report does not suppress in that year;
+    - ``exclude_signs`` that do not give +1 or -1 for exactly ``excludes``;
+    - a caseload and its spending head that are not suppressed together.
     """
 
-    hidden = {
-        (str(row.get("metric_id")), row.get("year")) for row in rows if _suppressed(row)
-    }
-    with_value, not_boolean, malformed, unmatched = [], [], [], []
+    by_key = {(str(row.get("metric_id")), row.get("year")): row for row in rows}
+    hidden = {key for key, row in by_key.items() if _suppressed(row)}
+    missing_fields, bad_years, with_value, not_boolean = [], [], [], []
+    malformed, bad_signs, unmatched, unpaired = [], [], [], []
     for row in rows:
-        label = f"{row.get('metric_id')} {row.get('year')}"
+        metric_id, year = str(row.get("metric_id")), row.get("year")
+        label = f"{metric_id} {year}"
+        if any(field not in row for field in SMALL_CELL_FIELDS):
+            missing_fields.append(label)
+        if isinstance(year, bool) or not isinstance(year, int):
+            bad_years.append(label)
         flag = row.get("suppressed", False)
         if not isinstance(flag, bool):
             not_boolean.append(label)
         elif flag and row.get("value") is not None:
             with_value.append(label)
+        if metric_id.startswith("caseloads."):
+            head = by_key.get((f"spending.{metric_id.split('.', 1)[1]}", year))
+            if head is not None and _suppressed(head) != _suppressed(row):
+                unpaired.append(label)
         excludes = row.get("excludes", [])
         if not isinstance(excludes, list) or not all(
-            isinstance(metric_id, str) for metric_id in excludes
+            isinstance(excluded, str) for excluded in excludes
         ):
             malformed.append(label)
             continue
+        if "exclude_signs" in row and _valid_signs(row) is None:
+            bad_signs.append(label)
         unmatched.extend(
-            f"{label} excludes {metric_id}"
-            for metric_id in excludes
-            if (metric_id, row.get("year")) not in hidden
+            f"{label} excludes {excluded}"
+            for excluded in excludes
+            if (excluded, year) not in hidden
         )
     problems = []
     for found, what in (
+        (
+            missing_fields,
+            "rows without the small-cell fields (suppressed, excludes, "
+            "exclude_signs), so from a tool that predates suppression",
+        ),
+        (bad_years, "metric rows whose year is not an integer"),
         (with_value, "suppressed figures with a value"),
         (not_boolean, "a suppressed flag that is not true or false"),
         (malformed, "excludes that are not a list of metric ids"),
+        (bad_signs, "exclude_signs that are not +1 or -1 for exactly its excludes"),
         (unmatched, "totals excluding a figure it does not suppress"),
+        (unpaired, "caseloads not suppressed together with their spending head"),
     ):
         if found:
             problems.append(f"the {name} report has {what}: {', '.join(found[:8])}")
     return problems
 
 
+#: Totals that are plain sums of heads in pounds, so a figure can be taken out
+#: by subtraction: the pinned tool's ``compare._additive`` (sections
+#: model_totals and balance, whose rows have kind ``model_total`` and
+#: ``balance``, and household net income). Decile means and the HBAI total
+#: (reset at zero) are not.
+ADDITIVE_KINDS = frozenset({"model_total", "balance"})
+ADDITIVE_METRICS = frozenset({"household.household_net_income"})
+
+
+def _additive(row: Mapping[str, Any]) -> bool:
+    return (
+        row.get("kind") in ADDITIVE_KINDS
+        or str(row.get("metric_id")) in ADDITIVE_METRICS
+    )
+
+
+def _aligned(
+    value: float,
+    own: Mapping[str, Any],
+    other_signs: Mapping[str, int],
+    metrics: Mapping[tuple[str, Optional[int]], Mapping[str, Any]],
+    year: Optional[int],
+) -> Optional[float]:
+    """``own``'s total with every figure only the other side excludes taken out.
+
+    As ``compare._aligned`` in the pinned tool: the figure's value is this
+    side's own published row for the year, and its sign is the one the side
+    that excludes it records. None when a needed figure is not published
+    here (missing, suppressed or not finite).
+    """
+
+    own_excludes = set(_excludes(own))
+    for metric_id, sign in sorted(other_signs.items()):
+        if metric_id in own_excludes:
+            continue
+        published = metrics.get((metric_id, year))
+        if (
+            published is None
+            or _suppressed(published)
+            or not _finite_number(published.get("value"))
+        ):
+            return None
+        value -= sign * float(published["value"])
+    return value
+
+
 def _wider_failure(candidate: Mapping[str, Any], previous: Mapping[str, Any]) -> bool:
     """Whether a check failing in both reports fails in a scope it did not before.
 
@@ -1414,30 +1515,38 @@ def compare_metric_reports(
     checks fail outright; known-defect checks fail only when they worsen
     against the previous pair, meaning the previous pair did not fail them,
     or failed them in fewer scopes (``failing_scopes``, when the tool reports
-    them); ``warn`` is recorded, and a check that newly warns needs review.
-    ``skipped`` means the check was not run, which is neither a pass nor a
-    failure: a skipped hard check, or a check skipped where the previous
-    pair ran it (pass, warn or fail), needs review.
+    them); ``warn`` is recorded, and a check that newly warns (it did not
+    warn in the previous report, as the tool's ``new_warning``) needs
+    review. ``skipped`` means the check was not run, which is neither a pass
+    nor a failure: a skipped hard check, or a check skipped where the
+    previous pair ran it (pass, warn or fail), needs review.
 
     A report with a status other than ``ok``, no metrics or no checks fails,
-    as does any check with a status outside ``CHECK_STATUSES``. A hard check
-    the previous pair ran that is missing from the candidate fails (the two
-    reports share one tool and one set of definitions); other missing checks
-    need review.
+    as does a report that repeats a check, or any check, in either report,
+    with a status outside ``CHECK_STATUSES``. A hard check the previous pair
+    ran that is missing from the candidate fails (the two reports share one
+    tool and one set of definitions); other missing checks need review.
 
     Small cells (W3's tool publishes a figure from fewer than 10 records as
     ``value`` null, ``suppressed`` true, and rebuilds every total that holds
-    one without it, listing it under ``excludes``):
+    one without it, listing it under ``excludes`` with its sign under
+    ``exclude_signs``):
 
     - a suppressed figure is present but never compared, and is not a
       non-finite value; suppressed on both sides, there is nothing to compare;
-    - a figure suppressed on one side only, or a total whose two sides leave
-      out different figures, is withheld: no change is computed (it would
-      give the suppressed figure back) and the comparison needs review. The
-      report lists the excluded ids without the sign each enters its total
-      with, so differing exclusions are never lined up here;
-    - a total compares numerically only when both sides exclude the same
-      figures;
+    - a figure suppressed on one side only is withheld: no change is
+      computed (it would come from fewer than 10 records) and the comparison
+      needs review;
+    - a total compares directly when both sides exclude the same figures;
+    - an additive total (``_additive``) whose sides exclude different
+      figures is lined up as the tool's ``compare._aligned`` does: each side
+      takes out, at its own published value and the excluding side's sign,
+      every figure only the other side excludes. The change between the
+      lined-up totals is held to the bound, whose relative part is taken on
+      the previous report's published total. Any other total with different
+      exclusions, or one that cannot be lined up (a needed figure not
+      published, or a figure both sides exclude with different signs), is
+      withheld for review;
     - a report that breaks the format (``_small_cell_problems``) fails.
     """
 
@@ -1452,6 +1561,27 @@ def compare_metric_reports(
             problems.append(f"the {name} report has no metrics")
         if not report.get("identities"):
             problems.append(f"the {name} report has no checks")
+        # One row per check: a repeated id would let either copy decide.
+        check_counts = Counter(
+            str(row.get("identity_id")) for row in report.get("identities", [])
+        )
+        repeated = sorted(check for check, count in check_counts.items() if count > 1)
+        if repeated:
+            problems.append(
+                f"the {name} report repeats checks: {', '.join(repeated[:8])}"
+            )
+    # The previous report's statuses decide regressions and new warnings, so
+    # an unknown one there is no more a pass than in the candidate.
+    previous_unknown = [
+        f"{row.get('identity_id')} ({row.get('status')!r})"
+        for row in previous.get("identities", [])
+        if row.get("status") not in CHECK_STATUSES
+    ]
+    if previous_unknown:
+        problems.append(
+            "the previous report has checks with an unknown status: "
+            + ", ".join(previous_unknown[:8])
+        )
     previous_rows = {
         str(row.get("identity_id")): row for row in previous.get("identities", [])
     }
@@ -1484,7 +1614,7 @@ def compare_metric_reports(
                 preexisting.append(check_id)
         elif status == "warn":
             warnings_.append(check_id)
-            if before == "pass":
+            if before != "warn":
                 new_warnings.append(check_id)
         elif status == "skipped":
             # Not run: never a pass, whatever the check's class.
@@ -1554,13 +1684,7 @@ def compare_metric_reports(
         nonfinite = [
             f"{row.get('metric_id')} {row.get('year')}"
             for row in rows
-            if not _suppressed(row)
-            and (
-                row.get("value") is None
-                or isinstance(row.get("value"), bool)
-                or not isinstance(row.get("value"), (int, float))
-                or not math.isfinite(float(row["value"]))
-            )
+            if not _suppressed(row) and not _finite_number(row.get("value"))
         ]
         if nonfinite:
             problems.append(
@@ -1577,9 +1701,11 @@ def compare_metric_reports(
         review.append(f"metrics have no baseline: {', '.join(without_baseline[:8])}")
     moves = []
     withheld: list[dict[str, Any]] = []
+    aligned_totals: list[str] = []
     suppressed_on_both = 0
+    # Years sort as text so a malformed year (failed above) cannot crash this.
     for key, row in sorted(
-        current.items(), key=lambda item: (item[0][0], item[0][1] or 0)
+        current.items(), key=lambda item: (item[0][0], str(item[0][1]))
     ):
         old = before_metrics.get(key)
         if old is None:
@@ -1599,47 +1725,83 @@ def compare_metric_reports(
                 }
             )
             continue
-        if _excludes(row) != _excludes(old):
-            # Each side leaves out its own suppressed figures; their
-            # difference would mix definitions and could give one back.
-            withheld.append(
-                {
-                    "metric_id": key[0],
-                    "year": key[1],
-                    "reason": "the reports leave out different suppressed figures",
-                    "candidate_excludes": list(_excludes(row)),
-                    "previous_excludes": list(_excludes(old)),
-                }
-            )
-            continue
-        try:
-            new_value, old_value = float(row["value"]), float(old["value"])
-        except (KeyError, TypeError, ValueError):
-            continue
-        if not (math.isfinite(new_value) and math.isfinite(old_value)):
+        if not (_finite_number(row.get("value")) and _finite_number(old.get("value"))):
             continue
+        new_value, old_value = float(row["value"]), float(old["value"])
+        new_compared, old_compared = new_value, old_value
+        aligned_on: Optional[list[str]] = None
+        if _excludes(row) != _excludes(old):
+            # Each side leaves out its own suppressed figures. Subtracting
+            # the totals as published would mix definitions and could give
+            # an excluded figure back, so they are lined up first, from
+            # published figures only, or withheld.
+            new_signs, old_signs = _valid_signs(row), _valid_signs(old)
+            reason = None
+            if not (_additive(row) and _additive(old)):
+                reason = "the reports leave out different suppressed figures"
+            elif new_signs is None or old_signs is None:
+                reason = (
+                    "the reports leave out different suppressed figures, "
+                    "without the signs needed to line them up"
+                )
+            elif any(
+                new_signs[metric_id] != old_signs[metric_id]
+                for metric_id in set(new_signs) & set(old_signs)
+            ):
+                reason = (
+                    "a figure both reports leave out enters their totals "
+                    "with different signs"
+                )
+            else:
+                lined_up = (
+                    _aligned(new_value, row, old_signs, current, key[1]),
+                    _aligned(old_value, old, new_signs, before_metrics, key[1]),
+                )
+                if lined_up[0] is None or lined_up[1] is None:
+                    reason = (
+                        "the reports leave out different suppressed figures, "
+                        "and one needed to line them up is not published"
+                    )
+                else:
+                    new_compared, old_compared = lined_up
+                    aligned_on = sorted(set(new_signs) | set(old_signs))
+                    aligned_totals.append(f"{key[0]} {key[1]}")
+            if reason is not None:
+                withheld.append(
+                    {
+                        "metric_id": key[0],
+                        "year": key[1],
+                        "reason": reason,
+                        "candidate_excludes": list(_excludes(row)),
+                        "previous_excludes": list(_excludes(old)),
+                    }
+                )
+                continue
         relative, absolute = _bound(bounds, row.get("kind"))
+        # The relative part is taken on the previous published total, as the
+        # tool's flag threshold is.
         threshold = max(relative * abs(old_value), absolute)
-        change = new_value - old_value
+        change = new_compared - old_compared
         if abs(change) > threshold:
-            moves.append(
-                {
-                    "metric_id": key[0],
-                    "year": key[1],
-                    "kind": row.get("kind"),
-                    "previous": old_value,
-                    "candidate": new_value,
-                    "change": change,
-                    "threshold": threshold,
-                }
-            )
+            move = {
+                "metric_id": key[0],
+                "year": key[1],
+                "kind": row.get("kind"),
+                "previous": old_value,
+                "candidate": new_value,
+                "change": change,
+                "threshold": threshold,
+            }
+            if aligned_on is not None:
+                move["lined_up_without"] = aligned_on
+            moves.append(move)
     if moves:
         review.append(f"{len(moves)} metric move(s) exceed their review bounds")
     if withheld:
         review.append(
             f"{len(withheld)} metric change(s) are withheld because a figure "
             "from fewer than 10 records is suppressed on one side, or the two "
-            "sides leave out different ones"
+            "sides leave out different ones and cannot be lined up"
         )
     evidence = {
         "metrics_version": candidate.get("metrics_version"),
@@ -1661,6 +1823,7 @@ def compare_metric_reports(
         ),
         "suppressed_on_both_sides": suppressed_on_both,
         "withheld_changes": withheld,
+        "lined_up_totals": aligned_totals,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
@@ -1726,6 +1889,29 @@ def metrics_review(
     )
 
 
+def publishable_metrics_report(report: Mapping[str, Any]) -> dict[str, Any]:
+    """A metrics report as it may be written to the qualification ledger.
+
+    The ledger is a branch of a public repository. A report that breaks the
+    small-cell format (``_small_cell_problems``) may carry a figure from
+    fewer than 10 records, so only its digest and its problems, which name
+    figures but give no values, are kept. A report the tool could not finish
+    has no metrics to check and is kept as it is.
+    """
+
+    problems = _small_cell_problems("metrics", report.get("metrics") or [])
+    if not problems:
+        return dict(report)
+    return {
+        "withheld": (
+            "This report breaks the metrics tool's small-cell format, so it "
+            "is not published."
+        ),
+        "report_sha256": evidence_sha256(report),
+        "problems": problems,
+    }
+
+
 # --- Reform responsiveness -------------------------------------------------------
 
 
@@ -1798,6 +1984,24 @@ def reform_responsiveness(
         disagreements.append(
             f"the report covers {report.get('years')}, not the horizon {list(years)}"
         )
+    # A repeated target or check would let either copy decide.
+    repeated = sorted(
+        f"{key[0]} {key[1]}"
+        for key, count in Counter(
+            (str(row.get("metric_id")), row.get("year"))
+            for row in report.get("metrics") or []
+        ).items()
+        if count > 1 and key[0].startswith("reform_targets.")
+    ) + sorted(
+        check
+        for check, count in Counter(
+            str(row.get("identity_id")) for row in report.get("identities") or []
+        ).items()
+        if count > 1 and check.startswith(("reform_runs:", "responsive:"))
+    )
+    if repeated:
+        disagreements.append(f"the report repeats {', '.join(repeated[:8])}")
+    malformed: list[str] = []
     for reform in standard_reforms:
         reform_id = reform["id"]
         sign = 1.0 if reform["direction"] == "up" else -1.0
@@ -1809,10 +2013,16 @@ def reform_responsiveness(
         for year in years:
             target = rows.get((f"reform_targets.{reform_id}", year)) or {}
             value = target.get("value")
-            changes[str(year)] = value
-            if _suppressed(target) and value is None:
-                withheld_years.append(year)
+            if _suppressed(target):
+                # Never copied into evidence, whatever the row carries.
+                changes[str(year)] = None
+                if value is None:
+                    withheld_years.append(year)
+                else:
+                    malformed.append(f"reform_targets.{reform_id} {year}")
+                    recomputed = False
                 continue
+            changes[str(year)] = value
             if (
                 isinstance(value, bool)
                 or not isinstance(value, (int, float))
@@ -1859,6 +2069,10 @@ def reform_responsiveness(
                     f"{responsive['status']} but its reform_targets values "
                     f"{'meet' if recomputed else 'do not meet'} the minimum"
                 )
+    if malformed:
+        disagreements.append(
+            "suppressed reform targets carry a value: " + ", ".join(malformed[:8])
+        )
     evidence = {
         "years": list(years),
         "reforms": table,
@@ -2959,7 +3173,7 @@ def gate_metrics() -> GateOutcome:
     results, evidence = run_gates(gates)
     for name, report in (state.get("metrics_reports") or {}).items():
         if report is not None:
-            evidence[f"metrics_report_{name}"] = report
+            evidence[f"metrics_report_{name}"] = publishable_metrics_report(report)
     return results, evidence
 
 
diff --git a/tests/fixtures/uk_metrics/README.md b/tests/fixtures/uk_metrics/README.md
index d45adc5a..166265e7 100644
--- a/tests/fixtures/uk_metrics/README.md
+++ b/tests/fixtures/uk_metrics/README.md
@@ -7,22 +7,25 @@ the report; never edit them by hand.
 
 - `budget_metrics_report.json`: a real `compute_budget_metrics` report from
   the tool's owner (workstream W3), at tool commit
-  `228a05a3e925beb50da619aa01e68c266e578fc0`, on the certified pair: uk-data
+  `1191ac5a473419f48e0c0643f83d31719da788e1`, on the certified pair: uk-data
   1.58.1 (`enhanced_frs_2024_25`) with policyengine-uk 2.130.1 and
   policyengine-core 3.33.0, for 2025-26 to 2031-32, with the overlap guard and
   the ten standard reforms. It holds aggregates only, under the tool's
   small-cell rule (`privacy.py`): a figure from fewer than 10 records is
   published as `value` null with `suppressed` true, and every total that
-  holds one is rebuilt without it and lists it under `excludes`. It has
-  1,484 metric rows (14 suppressed: Disabled Students' Allowance's total and
-  caseload in each of the seven years) and 350 checks.
+  holds one is rebuilt without it and lists it under `excludes`, with the
+  sign it enters with under `exclude_signs`. It has 1,484 metric rows (14
+  suppressed: Disabled Students' Allowance's total and caseload in each of
+  the seven years; 112 rows in 16 totals rebuilt without it) and 350 checks.
 - `standard_reforms.yaml`: the tool's standard reform set at the same commit,
   copied unchanged. Ten reforms, each with the model variable it must move,
   the direction and the least it must move it in every year (a fifth of its
   smallest yearly effect on the certified pair, adopted under cos d1344).
   The reform responsiveness gate reads the same file from the vendored tool.
 
-This report replaces a 1.58.0 report from before the tool suppressed small
-cells. That report published Disabled Students' Allowance, which comes from
+Its values, suppression and checks are byte-identical to W3's report at
+tool commit 228a05a3e, which first replaced the old fixture; 1191ac5a4 adds
+only `exclude_signs`. That replaced a 1.58.0 report from before the tool
+suppressed small cells. That report published Disabled Students' Allowance, which comes from
 fewer than 10 records, unsuppressed. Never commit a report from a tool
 commit that predates suppression.
diff --git a/tests/fixtures/uk_metrics/budget_metrics_report.json b/tests/fixtures/uk_metrics/budget_metrics_report.json
index 76fc0733..6e79f9c5 100644
--- a/tests/fixtures/uk_metrics/budget_metrics_report.json
+++ b/tests/fixtures/uk_metrics/budget_metrics_report.json
@@ -1,7 +1,7 @@
 {
  "schema": "policyengine-uk-aggregate-impact/1/report",
  "status": "ok",
- "metrics_version": "policyengine-uk-aggregate-impact/1+47b285096857148a+bb5198a0d8e7c046",
+ "metrics_version": "policyengine-uk-aggregate-impact/1+2e07ec2dcecd5de3+bb5198a0d8e7c046",
  "partition_version": "e8ea8a0198736e7cd9b0725148fdda717911033ee768eba044b58a8d46e9b0ef",
  "years": [
   2025,
@@ -19,6 +19,7 @@
    "value": 69513955.15348345,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -30,6 +31,7 @@
    "value": 69778110.5666471,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -41,6 +43,7 @@
    "value": 70036290.77594277,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -52,6 +55,7 @@
    "value": 70316432.3587328,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -63,6 +67,7 @@
    "value": 70625825.64596106,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -74,6 +79,7 @@
    "value": 70943644.05542476,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -85,6 +91,7 @@
    "value": 71248701.50975493,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -96,6 +103,7 @@
    "value": 35246926.333675,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -107,6 +115,7 @@
    "value": 35380865.871866405,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -118,6 +127,7 @@
    "value": 35511775.69777489,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -129,6 +139,7 @@
    "value": 35653820.972568765,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -140,6 +151,7 @@
    "value": 35810698.281318754,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -151,6 +163,7 @@
    "value": 35971847.531772316,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -162,6 +175,7 @@
    "value": 36126526.36007868,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -173,6 +187,7 @@
    "value": 31166694.04532416,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -184,6 +199,7 @@
    "value": 31285128.558958113,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -195,6 +211,7 @@
    "value": 31400884.081961572,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -206,6 +223,7 @@
    "value": 31526486.005968377,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -217,6 +235,7 @@
    "value": 31665202.984048083,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -228,6 +247,7 @@
    "value": 31807697.37639664,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -239,6 +259,7 @@
    "value": 31944470.379216716,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "population",
    "partition": null,
@@ -250,6 +271,7 @@
    "value": 297984459607.39465,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -261,6 +283,7 @@
    "value": 317782510223.38354,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -272,6 +295,7 @@
    "value": 335140035823.943,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -283,6 +307,7 @@
    "value": 350031424626.733,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -294,6 +319,7 @@
    "value": 366458443148.21484,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -305,6 +331,7 @@
    "value": 384662297800.91766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -316,6 +343,7 @@
    "value": 403275325039.3891,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "income_tax",
@@ -327,6 +355,7 @@
    "value": 52575017190.03174,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -338,6 +367,7 @@
    "value": 54941380589.82846,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -349,6 +379,7 @@
    "value": 56752394914.42203,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -360,6 +391,7 @@
    "value": 58476221815.846825,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -371,6 +403,7 @@
    "value": 60511486452.76118,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -382,6 +415,7 @@
    "value": 62445204124.271996,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -393,6 +427,7 @@
    "value": 64898705801.9577,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_individual",
@@ -404,6 +439,7 @@
    "value": 152640935215.8076,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -415,6 +451,7 @@
    "value": 159182492481.57574,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -426,6 +463,7 @@
    "value": 164141628899.95114,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -437,6 +475,7 @@
    "value": 168731462725.2504,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -448,6 +487,7 @@
    "value": 175566267043.68347,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -459,6 +499,7 @@
    "value": 181079291564.9595,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -470,6 +511,7 @@
    "value": 188223742975.49728,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "nics_employer",
@@ -481,6 +523,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -492,6 +535,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -503,6 +547,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -514,6 +559,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -525,6 +571,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -536,6 +583,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -547,6 +595,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_capital",
@@ -558,6 +607,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -569,6 +619,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -580,6 +631,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -591,6 +643,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -602,6 +655,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -613,6 +667,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -624,6 +679,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "employer_nics_response_consumer",
@@ -635,6 +691,7 @@
    "value": 12618588087.194477,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -646,6 +703,7 @@
    "value": 13055343054.272093,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -657,6 +715,7 @@
    "value": 13547024733.440294,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -668,6 +727,7 @@
    "value": 14041998268.40096,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -679,6 +739,7 @@
    "value": 14540347118.814587,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -690,6 +751,7 @@
    "value": 15086908668.221151,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -701,6 +763,7 @@
    "value": 15645569134.728756,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "capital_gains_tax",
@@ -712,6 +775,7 @@
    "value": 7826615852.272217,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -723,6 +787,7 @@
    "value": 8123473394.454311,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -734,6 +799,7 @@
    "value": 8349215176.222883,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -745,6 +811,7 @@
    "value": 8558646443.275475,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -756,6 +823,7 @@
    "value": 8785423316.325344,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -767,6 +835,7 @@
    "value": 9036756985.870995,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -778,6 +847,7 @@
    "value": 9376925443.173416,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "student_loan_repayments",
@@ -789,6 +859,7 @@
    "value": 313127412006.5256,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -800,6 +871,7 @@
    "value": 321546605195.24274,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -811,6 +883,7 @@
    "value": 329191061310.5304,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -822,6 +895,7 @@
    "value": 337117963034.16547,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -833,6 +907,7 @@
    "value": 345373312536.52356,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -844,6 +919,7 @@
    "value": 353866055269.635,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -855,6 +931,7 @@
    "value": 362495430544.1016,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat",
@@ -866,6 +943,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -877,6 +955,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -888,6 +967,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -899,6 +979,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -910,6 +991,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -921,6 +1003,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -932,6 +1015,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vat_change",
@@ -943,6 +1027,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -954,6 +1039,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -965,6 +1051,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -976,6 +1063,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -987,6 +1075,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -998,6 +1087,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -1009,6 +1099,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "private_school_vat",
@@ -1020,6 +1111,7 @@
    "value": 24534379561.8306,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1031,6 +1123,7 @@
    "value": 24639271891.62144,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1042,6 +1135,7 @@
    "value": 26638194760.36437,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1053,6 +1147,7 @@
    "value": 26694679049.418755,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1064,6 +1159,7 @@
    "value": 26418117577.300167,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1075,6 +1171,7 @@
    "value": 25760349910.6802,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1086,6 +1183,7 @@
    "value": 26353950047.77822,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "fuel_duty",
@@ -1097,6 +1195,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1108,6 +1207,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1119,6 +1219,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1130,6 +1231,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1141,6 +1243,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1152,6 +1255,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1163,6 +1267,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "alcohol_duty",
@@ -1174,6 +1279,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1185,6 +1291,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1196,6 +1303,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1207,6 +1315,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1218,6 +1327,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1229,6 +1339,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1240,6 +1351,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tobacco_duty",
@@ -1251,6 +1363,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1262,6 +1375,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1273,6 +1387,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1284,6 +1399,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1295,6 +1411,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1306,6 +1423,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1317,6 +1435,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "vehicle_excise_duty",
@@ -1328,6 +1447,7 @@
    "value": 4275969952.7872777,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1339,6 +1459,7 @@
    "value": 4427595383.179631,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1350,6 +1471,7 @@
    "value": 4444328769.554615,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1361,6 +1483,7 @@
    "value": 4464697036.417519,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1372,6 +1495,7 @@
    "value": 4485128769.03225,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1383,6 +1507,7 @@
    "value": 4506096907.015281,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1394,6 +1519,7 @@
    "value": 4526586455.751576,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "tv_licence",
@@ -1405,6 +1531,7 @@
    "value": 49560513009.82745,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1416,6 +1543,7 @@
    "value": 52449635526.310104,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1427,6 +1555,7 @@
    "value": 55778039679.1455,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1438,6 +1567,7 @@
    "value": 59386561832.62195,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1449,6 +1579,7 @@
    "value": 62981354541.126625,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1460,6 +1591,7 @@
    "value": 66736811407.45229,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1471,6 +1603,7 @@
    "value": 70704732540.45876,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "council_tax",
@@ -1482,6 +1615,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1493,6 +1627,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1504,6 +1639,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1515,6 +1651,7 @@
    "value": 483900104.6233177,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1526,6 +1663,7 @@
    "value": 495749379.82161856,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1537,6 +1675,7 @@
    "value": 507938784.7696847,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1548,6 +1687,7 @@
    "value": 520325557.6779943,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "high_value_council_tax_surcharge",
@@ -1559,6 +1699,7 @@
    "value": 552492559.6753057,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1570,6 +1711,7 @@
    "value": 578605888.7461181,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1581,6 +1723,7 @@
    "value": 605893088.8719264,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1592,6 +1735,7 @@
    "value": 634656724.1676605,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1603,6 +1747,7 @@
    "value": 665050775.6261593,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1614,6 +1759,7 @@
    "value": 696969823.2250919,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1625,6 +1771,7 @@
    "value": 730275344.6123755,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "domestic_rates",
@@ -1636,6 +1783,7 @@
    "value": 31732501414.791157,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1647,6 +1795,7 @@
    "value": 31732500125.540802,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1658,6 +1807,7 @@
    "value": 31732498126.72371,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1669,6 +1819,7 @@
    "value": 31732499316.105175,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1680,6 +1831,7 @@
    "value": 31732494964.235413,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1691,6 +1843,7 @@
    "value": 31732498638.635994,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1702,6 +1855,7 @@
    "value": 31732494471.035408,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "business_rates",
@@ -1713,6 +1867,7 @@
    "value": 19073759714.657246,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1724,6 +1879,7 @@
    "value": 20077204232.549347,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1735,6 +1891,7 @@
    "value": 21035871774.44113,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1746,6 +1903,7 @@
    "value": 21999031263.396732,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1757,6 +1915,7 @@
    "value": 22985619104.754326,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1768,6 +1927,7 @@
    "value": 24063362268.549835,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1779,6 +1939,7 @@
    "value": 25218986028.960094,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "sdlt_household",
@@ -1790,6 +1951,7 @@
    "value": 3441794.3282832364,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1801,6 +1963,7 @@
    "value": 3718451.781090757,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1812,6 +1975,7 @@
    "value": 4036378.263004425,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1823,6 +1987,7 @@
    "value": 4360394.001039479,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1834,6 +1999,7 @@
    "value": 4685725.303715903,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1845,6 +2011,7 @@
    "value": 5044918.447127742,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1856,6 +2023,7 @@
    "value": 5422944.119211734,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_transaction_tax",
@@ -1867,6 +2035,7 @@
    "value": 109691161.84922537,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1878,6 +2047,7 @@
    "value": 114611758.83902286,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1889,6 +2059,7 @@
    "value": 120242919.16397013,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1900,6 +2071,7 @@
    "value": 125932263.95004636,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1911,6 +2083,7 @@
    "value": 131640517.58306551,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1922,6 +2095,7 @@
    "value": 137912689.4621755,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1933,6 +2107,7 @@
    "value": 144400087.45167437,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_and_buildings_transaction_tax",
@@ -1944,6 +2119,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1955,6 +2131,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1966,6 +2143,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1977,6 +2155,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1988,6 +2167,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -1999,6 +2179,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -2010,6 +2191,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "corporate_incident_tax_change",
@@ -2021,6 +2203,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2032,6 +2215,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2043,6 +2227,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2054,6 +2239,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2065,6 +2251,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2076,6 +2263,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2087,6 +2275,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "consumer_incident_tax_change",
@@ -2098,6 +2287,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2109,6 +2299,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2120,6 +2311,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2131,6 +2323,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2142,6 +2335,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2153,6 +2347,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2164,6 +2359,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "wealth_tax",
@@ -2175,6 +2371,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2186,6 +2383,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2197,6 +2395,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2208,6 +2407,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2219,6 +2419,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2230,6 +2431,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2241,6 +2443,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "non_primary_residence_wealth_tax",
@@ -2252,6 +2455,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2263,6 +2467,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2274,6 +2479,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2285,6 +2491,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2296,6 +2503,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2307,6 +2515,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2318,6 +2527,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "land_value_tax",
@@ -2329,6 +2539,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2340,6 +2551,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2351,6 +2563,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2362,6 +2575,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2373,6 +2587,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2384,6 +2599,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2395,6 +2611,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "receipt",
    "partition": "carbon_tax",
@@ -2406,6 +2623,7 @@
    "value": 122503036176.28136,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2417,6 +2635,7 @@
    "value": 127115003712.11774,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2428,6 +2647,7 @@
    "value": 128280611587.4219,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2439,6 +2659,7 @@
    "value": 130209285651.49004,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2450,6 +2671,7 @@
    "value": 134051705144.42847,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2461,6 +2683,7 @@
    "value": 138021583333.92395,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2472,6 +2695,7 @@
    "value": 142080411583.76672,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "state_pension",
@@ -2483,6 +2707,7 @@
    "value": 11307942.897278756,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2494,6 +2719,7 @@
    "value": 11208358.708708271,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2505,6 +2731,7 @@
    "value": 10906221.550106525,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2516,6 +2743,7 @@
    "value": 10811938.301638946,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2527,6 +2755,7 @@
    "value": 10859510.9701875,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2538,6 +2767,7 @@
    "value": 10908379.084595531,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2549,6 +2779,7 @@
    "value": 10955285.089603484,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "state_pension",
@@ -2560,6 +2791,7 @@
    "value": 6683600257.719555,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2571,6 +2803,7 @@
    "value": 7056299099.336407,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2582,6 +2815,7 @@
    "value": 7040775597.466119,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2593,6 +2827,7 @@
    "value": 7110102297.589521,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2604,6 +2839,7 @@
    "value": 7231026514.317166,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2615,6 +2851,7 @@
    "value": 7365763489.682707,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2626,6 +2863,7 @@
    "value": 7463303552.117271,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pension_credit",
@@ -2637,6 +2875,7 @@
    "value": 1490774.5672746152,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2648,6 +2887,7 @@
    "value": 1489116.733679533,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2659,6 +2899,7 @@
    "value": 1477429.6021682024,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2670,6 +2911,7 @@
    "value": 1455339.335629344,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2681,6 +2923,7 @@
    "value": 1457221.2425712496,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2692,6 +2935,7 @@
    "value": 1454060.4666527808,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2703,6 +2947,7 @@
    "value": 1450518.8676682264,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pension_credit",
@@ -2714,6 +2959,7 @@
    "value": 1696782924.1721363,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2725,6 +2971,7 @@
    "value": 1679283343.732223,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2736,6 +2983,7 @@
    "value": 1590003738.0768867,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2747,6 +2995,7 @@
    "value": 1573027080.7015598,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2758,6 +3007,7 @@
    "value": 1569952442.020166,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2769,6 +3019,7 @@
    "value": 1547501174.76131,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2780,6 +3031,7 @@
    "value": 1519503572.7274477,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "winter_fuel_payment",
@@ -2791,6 +3043,7 @@
    "value": 7090970.121831879,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2802,6 +3055,7 @@
    "value": 7007600.1749506295,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2813,6 +3067,7 @@
    "value": 6593488.894350678,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2824,6 +3079,7 @@
    "value": 6508639.181520969,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2835,6 +3091,7 @@
    "value": 6490585.181142107,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2846,6 +3103,7 @@
    "value": 6377424.451988548,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2857,6 +3115,7 @@
    "value": 6242475.78672789,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "winter_fuel_payment",
@@ -2868,6 +3127,7 @@
    "value": 190004357.0627768,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2879,6 +3139,7 @@
    "value": 197376523.34808874,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2890,6 +3151,7 @@
    "value": 201464846.70418116,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2901,6 +3163,7 @@
    "value": 205237714.89489964,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2912,6 +3175,7 @@
    "value": 210263123.1305548,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2923,6 +3187,7 @@
    "value": 215433546.71501532,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2934,6 +3199,7 @@
    "value": 220687250.38609877,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pawhp",
@@ -2945,6 +3211,7 @@
    "value": 806440.3659721613,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2956,6 +3223,7 @@
    "value": 806642.316529274,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2967,6 +3235,7 @@
    "value": 806823.3181906939,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2978,6 +3247,7 @@
    "value": 805142.1836649776,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -2989,6 +3259,7 @@
    "value": 808684.8276723027,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -3000,6 +3271,7 @@
    "value": 812323.9398192763,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -3011,6 +3283,7 @@
    "value": 815816.9233164787,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pawhp",
@@ -3022,6 +3295,7 @@
    "value": 79166098634.76385,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3033,6 +3307,7 @@
    "value": 83483281466.41425,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3044,6 +3319,7 @@
    "value": 85110190875.9473,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3055,6 +3331,7 @@
    "value": 86667339883.95622,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3066,6 +3343,7 @@
    "value": 87402948162.99124,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3077,6 +3355,7 @@
    "value": 84214027875.53,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3088,6 +3367,7 @@
    "value": 85457636655.59526,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_credit",
@@ -3099,6 +3379,7 @@
    "value": 6371587.519835666,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3110,6 +3391,7 @@
    "value": 6379016.747252494,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3121,6 +3403,7 @@
    "value": 6394538.736335561,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3132,6 +3415,7 @@
    "value": 6399621.182661429,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3143,6 +3427,7 @@
    "value": 6373153.488585249,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3154,6 +3439,7 @@
    "value": 6316123.800888762,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3165,6 +3451,7 @@
    "value": 6311765.528904498,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_credit",
@@ -3176,6 +3463,7 @@
    "value": 8595335171.520943,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3187,6 +3475,7 @@
    "value": 8931864198.577654,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3198,6 +3487,7 @@
    "value": 9199477872.067867,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3209,6 +3499,7 @@
    "value": 9343759945.943094,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3220,6 +3511,7 @@
    "value": 9621753903.580982,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3231,6 +3523,7 @@
    "value": 9883322170.08307,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3242,6 +3535,7 @@
    "value": 10165697938.801252,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "housing_benefit",
@@ -3253,6 +3547,7 @@
    "value": 1254488.0164678842,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3264,6 +3559,7 @@
    "value": 1252740.275393933,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3275,6 +3571,7 @@
    "value": 1254335.1581986696,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3286,6 +3583,7 @@
    "value": 1240028.0728783756,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3297,6 +3595,7 @@
    "value": 1244626.769205615,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3308,6 +3607,7 @@
    "value": 1246801.715999484,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3319,6 +3619,7 @@
    "value": 1249258.3732767105,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "housing_benefit",
@@ -3330,6 +3631,7 @@
    "value": 1988515658.8280945,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3341,6 +3643,7 @@
    "value": 2033885987.1873639,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3352,6 +3655,7 @@
    "value": 2079220973.3377244,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3363,6 +3667,7 @@
    "value": 2130392978.7542346,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3374,6 +3679,7 @@
    "value": 2182371431.2323685,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3385,6 +3691,7 @@
    "value": 2245332431.4065833,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3396,6 +3703,7 @@
    "value": 2299546088.50543,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "council_tax_reduction",
@@ -3407,6 +3715,7 @@
    "value": 3187241.3228853345,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3418,6 +3727,7 @@
    "value": 3211653.8483200073,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3429,6 +3739,7 @@
    "value": 3226461.487433046,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3440,6 +3751,7 @@
    "value": 3249134.5323915184,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3451,6 +3763,7 @@
    "value": 3264581.2450436354,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3462,6 +3775,7 @@
    "value": 3296161.365950793,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3473,6 +3787,7 @@
    "value": 3310563.1543370783,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "council_tax_reduction",
@@ -3484,6 +3799,7 @@
    "value": 2119219755.27102,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3495,6 +3811,7 @@
    "value": 2175740626.0724893,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3506,6 +3823,7 @@
    "value": 2226624100.582522,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3517,6 +3835,7 @@
    "value": 2277324834.952569,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3528,6 +3847,7 @@
    "value": 2332267574.159017,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3539,6 +3859,7 @@
    "value": 2388837175.037817,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3550,6 +3871,7 @@
    "value": 2446074707.6473985,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_income",
@@ -3561,6 +3883,7 @@
    "value": 186830.98939606547,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3572,6 +3895,7 @@
    "value": 187540.95343746245,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3583,6 +3907,7 @@
    "value": 188234.8581573367,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3594,6 +3919,7 @@
    "value": 188797.70078976452,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3605,6 +3931,7 @@
    "value": 189628.41371196508,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3616,6 +3943,7 @@
    "value": 190481.74765598774,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3627,6 +3955,7 @@
    "value": 191300.81845253706,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_income",
@@ -3638,6 +3967,7 @@
    "value": 5221642514.164815,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3649,6 +3979,7 @@
    "value": 5362038966.389469,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3660,6 +3991,7 @@
    "value": 5489516286.663287,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3671,6 +4003,7 @@
    "value": 5621703470.566074,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3682,6 +4015,7 @@
    "value": 5759367828.016521,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3693,6 +4027,7 @@
    "value": 5900990569.133743,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3704,6 +4039,7 @@
    "value": 6044892357.516051,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "esa_contrib",
@@ -3715,6 +4051,7 @@
    "value": 721684.3135545999,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3726,6 +4063,7 @@
    "value": 724426.7398380041,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3737,6 +4075,7 @@
    "value": 727107.1310208887,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3748,6 +4087,7 @@
    "value": 730015.5208309293,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3759,6 +4099,7 @@
    "value": 733227.5983880013,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3770,6 +4111,7 @@
    "value": 736527.1409217119,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3781,6 +4123,7 @@
    "value": 739694.2040582746,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "esa_contrib",
@@ -3792,6 +4135,7 @@
    "value": 1446979.5182146362,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3803,6 +4147,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3814,6 +4159,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3825,6 +4171,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3836,6 +4183,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3847,6 +4195,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3858,6 +4207,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_income",
@@ -3869,6 +4219,7 @@
    "value": 278.16873490810394,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3880,6 +4231,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3891,6 +4243,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3902,6 +4255,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3913,6 +4267,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3924,6 +4279,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3935,6 +4291,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_income",
@@ -3946,6 +4303,7 @@
    "value": 288777970.5356167,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3957,6 +4315,7 @@
    "value": 296542457.71586204,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3968,6 +4327,7 @@
    "value": 303592471.1494838,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3979,6 +4339,7 @@
    "value": 310902955.13914746,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -3990,6 +4351,7 @@
    "value": 318516348.7643643,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -4001,6 +4363,7 @@
    "value": 326348673.79918647,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -4012,6 +4375,7 @@
    "value": 334307010.21562654,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "jsa_contrib",
@@ -4023,6 +4387,7 @@
    "value": 67182.8121483326,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4034,6 +4399,7 @@
    "value": 67438.10866451263,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4045,6 +4411,7 @@
    "value": 67687.63075757027,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4056,6 +4423,7 @@
    "value": 67958.37626743317,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4067,6 +4435,7 @@
    "value": 68257.39367341995,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4078,6 +4447,7 @@
    "value": 68564.55532884598,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4089,6 +4459,7 @@
    "value": 68859.38249921799,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "jsa_contrib",
@@ -4100,6 +4471,7 @@
    "value": 123955194.70721354,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4111,6 +4483,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4122,6 +4495,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4133,6 +4507,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4144,6 +4519,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4155,6 +4531,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4166,6 +4543,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "income_support",
@@ -4177,6 +4555,7 @@
    "value": 24803.04834920168,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4188,6 +4567,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4199,6 +4579,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4210,6 +4591,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4221,6 +4603,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4232,6 +4615,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4243,6 +4627,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "income_support",
@@ -4254,6 +4639,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4265,6 +4651,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4276,6 +4663,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4287,6 +4675,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4298,6 +4687,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4309,6 +4699,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4320,6 +4711,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "working_tax_credit",
@@ -4331,6 +4723,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4342,6 +4735,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4353,6 +4747,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4364,6 +4759,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4375,6 +4771,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4386,6 +4783,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4397,6 +4795,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "working_tax_credit",
@@ -4408,6 +4807,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4419,6 +4819,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4430,6 +4831,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4441,6 +4843,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4452,6 +4855,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4463,6 +4867,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4474,6 +4879,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_tax_credit",
@@ -4485,6 +4891,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4496,6 +4903,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4507,6 +4915,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4518,6 +4927,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4529,6 +4939,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4540,6 +4951,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4551,6 +4963,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_tax_credit",
@@ -4562,6 +4975,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4573,6 +4987,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4584,6 +4999,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4595,6 +5011,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4606,6 +5023,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4617,6 +5035,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4628,6 +5047,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "incapacity_benefit",
@@ -4639,6 +5059,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4650,6 +5071,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4661,6 +5083,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4672,6 +5095,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4683,6 +5107,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4694,6 +5119,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4705,6 +5131,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "incapacity_benefit",
@@ -4716,6 +5143,7 @@
    "value": 27050796518.958164,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4727,6 +5155,7 @@
    "value": 28187504820.35819,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4738,6 +5167,7 @@
    "value": 28942448438.6212,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4749,6 +5179,7 @@
    "value": 29639334288.533737,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4760,6 +5191,7 @@
    "value": 30365112782.59276,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4771,6 +5203,7 @@
    "value": 31111725337.197277,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4782,6 +5215,7 @@
    "value": 31870426624.368805,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "pip",
@@ -4793,6 +5227,7 @@
    "value": 3581346.50325121,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4804,6 +5239,7 @@
    "value": 3594955.7513322085,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4815,6 +5251,7 @@
    "value": 3608257.1502955705,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4826,6 +5263,7 @@
    "value": 3622690.0020009577,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4837,6 +5275,7 @@
    "value": 3638629.8922510594,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4848,6 +5287,7 @@
    "value": 3655003.834502399,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4859,6 +5299,7 @@
    "value": 3670720.34740828,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "pip",
@@ -4870,6 +5311,7 @@
    "value": 7519515429.343498,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4881,6 +5323,7 @@
    "value": 7834750092.336622,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4892,6 +5335,7 @@
    "value": 8044587394.8355665,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4903,6 +5347,7 @@
    "value": 8238287553.0089445,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4914,6 +5359,7 @@
    "value": 8440018870.958048,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4925,6 +5371,7 @@
    "value": 8647540725.08345,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4936,6 +5383,7 @@
    "value": 8858422643.224787,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dla",
@@ -4947,6 +5395,7 @@
    "value": 1296293.76486139,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4958,6 +5407,7 @@
    "value": 1301219.7249682397,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4969,6 +5419,7 @@
    "value": 1306034.2623415291,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4980,6 +5431,7 @@
    "value": 1311258.3262985945,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -4991,6 +5443,7 @@
    "value": 1317027.8841654807,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -5002,6 +5455,7 @@
    "value": 1322954.550306335,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -5013,6 +5467,7 @@
    "value": 1328643.2488841116,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "dla",
@@ -5024,6 +5479,7 @@
    "value": 8713069613.537264,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5035,6 +5491,7 @@
    "value": 9078584120.844625,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5046,6 +5503,7 @@
    "value": 9321734807.6616,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5057,6 +5515,7 @@
    "value": 9546186520.166021,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5068,6 +5527,7 @@
    "value": 9779944679.35845,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5079,6 +5539,7 @@
    "value": 10020412141.96302,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5090,6 +5551,7 @@
    "value": 10264773293.632841,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "attendance_allowance",
@@ -5101,6 +5563,7 @@
    "value": 1701405.523672521,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5112,6 +5575,7 @@
    "value": 1707870.9254432172,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5123,6 +5587,7 @@
    "value": 1714190.0767204762,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5134,6 +5599,7 @@
    "value": 1721046.7521996498,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5145,6 +5611,7 @@
    "value": 1728619.3880579919,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5156,6 +5623,7 @@
    "value": 1736398.2265275419,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5167,6 +5635,7 @@
    "value": 1743864.7361019552,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "attendance_allowance",
@@ -5178,6 +5647,7 @@
    "value": 4498304384.942733,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5189,6 +5659,7 @@
    "value": 4686148233.621847,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5200,6 +5671,7 @@
    "value": 4811656899.117326,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5211,6 +5683,7 @@
    "value": 4927513579.343729,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5222,6 +5695,7 @@
    "value": 5048174373.178411,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5233,6 +5707,7 @@
    "value": 5168683430.088493,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5244,6 +5719,7 @@
    "value": 5294728594.298446,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carers_allowance",
@@ -5255,6 +5731,7 @@
    "value": 1038485.6135211289,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5266,6 +5743,7 @@
    "value": 1042431.8938074112,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5277,6 +5755,7 @@
    "value": 1046288.9127022028,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5288,6 +5767,7 @@
    "value": 1050474.0211501122,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5299,6 +5779,7 @@
    "value": 1055096.1227512658,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5310,6 +5791,7 @@
    "value": 1059103.4548994005,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5321,6 +5803,7 @@
    "value": 1063657.5973686576,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carers_allowance",
@@ -5332,6 +5815,7 @@
    "value": 352284662.9714799,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5343,6 +5827,7 @@
    "value": 366995656.0579343,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5354,6 +5839,7 @@
    "value": 376824870.322693,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5365,6 +5851,7 @@
    "value": 385898182.16357577,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5376,6 +5863,7 @@
    "value": 395347728.7181926,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5387,6 +5875,7 @@
    "value": 405068460.50986433,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5398,6 +5887,7 @@
    "value": 414946587.8089589,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "carer_support_payment",
@@ -5409,6 +5899,7 @@
    "value": 81328.99044907093,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5420,6 +5911,7 @@
    "value": 81638.04422974586,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5431,6 +5923,7 @@
    "value": 81940.10755866766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5442,6 +5935,7 @@
    "value": 82267.86362826824,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5453,6 +5947,7 @@
    "value": 82629.84296369553,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5464,6 +5959,7 @@
    "value": 83001.67959588766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5475,6 +5971,7 @@
    "value": 83358.58633065224,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "carer_support_payment",
@@ -5486,6 +5983,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5497,6 +5995,7 @@
    "value": 49668588.102493696,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5508,6 +6007,7 @@
    "value": 49852363.43918431,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5519,6 +6019,7 @@
    "value": 50051770.239931166,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5530,6 +6031,7 @@
    "value": 50271998.47644251,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5541,6 +6043,7 @@
    "value": 50498223.892546244,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5552,6 +6055,7 @@
    "value": 50715365.95869056,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_carer_supplement",
@@ -5563,6 +6067,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5574,6 +6079,7 @@
    "value": 81638.04422974586,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5585,6 +6091,7 @@
    "value": 81940.10755866766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5596,6 +6103,7 @@
    "value": 82267.86362826824,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5607,6 +6115,7 @@
    "value": 82629.84296369553,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5618,6 +6127,7 @@
    "value": 83001.67959588766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5629,6 +6139,7 @@
    "value": 83358.58633065224,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_carer_supplement",
@@ -5640,6 +6151,7 @@
    "value": 26001911.186065674,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5651,6 +6163,7 @@
    "value": 27088007.985394344,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5662,6 +6175,7 @@
    "value": 27813501.58527428,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5673,6 +6187,7 @@
    "value": 28483206.305987563,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5684,6 +6199,7 @@
    "value": 29180676.754239403,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5695,6 +6211,7 @@
    "value": 29898167.047436927,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5706,6 +6223,7 @@
    "value": 30627272.264840692,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "sda",
@@ -5717,6 +6235,7 @@
    "value": 4348.145683288574,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5728,6 +6247,7 @@
    "value": 4364.668739795685,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5739,6 +6259,7 @@
    "value": 4380.818064212799,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5750,6 +6271,7 @@
    "value": 4398.341153144836,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5761,6 +6283,7 @@
    "value": 4417.694038391113,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5772,6 +6295,7 @@
    "value": 4437.573884487152,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5783,6 +6307,7 @@
    "value": 4456.655462741852,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "sda",
@@ -5794,6 +6319,7 @@
    "value": 505396316.7142715,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5805,6 +6331,7 @@
    "value": 518985130.7359581,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5816,6 +6343,7 @@
    "value": 531323482.42515385,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5827,6 +6355,7 @@
    "value": 544117734.2383146,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5838,6 +6367,7 @@
    "value": 557442066.9128101,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5849,6 +6379,7 @@
    "value": 571149605.5284191,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5860,6 +6391,7 @@
    "value": 585077668.0455391,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "iidb",
@@ -5871,6 +6403,7 @@
    "value": 137473.5583550036,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5882,6 +6415,7 @@
    "value": 137995.96156597137,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5893,6 +6427,7 @@
    "value": 138506.54905071855,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5904,6 +6439,7 @@
    "value": 139060.56764179468,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5915,6 +6451,7 @@
    "value": 139672.4357754588,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5926,6 +6463,7 @@
    "value": 140300.96557214856,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5937,6 +6475,7 @@
    "value": 140904.25975701213,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "iidb",
@@ -5948,6 +6487,7 @@
    "value": 608337715.55495,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -5959,6 +6499,7 @@
    "value": 624694356.9666108,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -5970,6 +6511,7 @@
    "value": 639545878.8404102,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -5981,6 +6523,7 @@
    "value": 654946115.3175836,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -5992,6 +6535,7 @@
    "value": 670984438.3106201,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -6003,6 +6547,7 @@
    "value": 687483985.4915761,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -6014,6 +6559,7 @@
    "value": 704248973.1763016,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "afcs",
@@ -6025,6 +6571,7 @@
    "value": 93556.20288914442,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6036,6 +6583,7 @@
    "value": 93911.72057116032,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6047,6 +6595,7 @@
    "value": 94259.19729825854,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6058,6 +6607,7 @@
    "value": 94636.23070755601,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6069,6 +6619,7 @@
    "value": 95052.63239446282,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6080,6 +6631,7 @@
    "value": 95480.37335321307,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6091,6 +6643,7 @@
    "value": 95890.9378361702,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "afcs",
@@ -6102,6 +6655,7 @@
    "value": 16193470845.603186,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6113,6 +6667,7 @@
    "value": 16865082606.210407,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6124,6 +6679,7 @@
    "value": 17309224587.32687,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6135,6 +6691,7 @@
    "value": 17722732649.511974,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6146,6 +6703,7 @@
    "value": 18149355497.8589,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6157,6 +6715,7 @@
    "value": 18589683648.812527,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6168,6 +6727,7 @@
    "value": 19019347515.30189,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "child_benefit",
@@ -6179,6 +6739,7 @@
    "value": 8124933.04077065,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6190,6 +6751,7 @@
    "value": 8151661.30214186,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6201,6 +6763,7 @@
    "value": 8178496.28433007,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6212,6 +6775,7 @@
    "value": 8209901.52580525,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6223,6 +6787,7 @@
    "value": 8242994.678169802,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6234,6 +6799,7 @@
    "value": 8277445.224295765,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6245,6 +6811,7 @@
    "value": 8301138.966311127,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "child_benefit",
@@ -6256,6 +6823,7 @@
    "value": 496826543.81597674,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6267,6 +6835,7 @@
    "value": 518442587.758203,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6278,6 +6847,7 @@
    "value": 532354940.6639104,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6289,6 +6859,7 @@
    "value": 545600150.271133,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6300,6 +6871,7 @@
    "value": 557257209.815226,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6311,6 +6883,7 @@
    "value": 570941579.8039502,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6322,6 +6895,7 @@
    "value": 579837131.7746521,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "scottish_child_payment",
@@ -6333,6 +6907,7 @@
    "value": 351909.9919484854,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6344,6 +6919,7 @@
    "value": 353547.8581060171,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6355,6 +6931,7 @@
    "value": 354855.99119508266,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6366,6 +6943,7 @@
    "value": 356275.3960905075,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6377,6 +6955,7 @@
    "value": 356621.7960590124,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6388,6 +6967,7 @@
    "value": 358226.60453784466,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6399,6 +6979,7 @@
    "value": 356674.22713041306,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "scottish_child_payment",
@@ -6410,6 +6991,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6421,6 +7003,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6432,6 +7015,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6443,6 +7027,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6454,6 +7039,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6465,6 +7051,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6476,6 +7063,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "two_child_limit_payment",
@@ -6487,6 +7075,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6498,6 +7087,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6509,6 +7099,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6520,6 +7111,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6531,6 +7123,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6542,6 +7135,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6553,6 +7147,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "two_child_limit_payment",
@@ -6564,6 +7159,7 @@
    "value": 52030589.486631,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6575,6 +7171,7 @@
    "value": 52228307.60199582,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6586,6 +7183,7 @@
    "value": 52421553.321768366,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6597,6 +7195,7 @@
    "value": 52631236.984368056,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6608,6 +7207,7 @@
    "value": 52862815.027035154,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6619,6 +7219,7 @@
    "value": 53100698.99261543,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6630,6 +7231,7 @@
    "value": 53329031.82253713,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "healthy_start_vouchers",
@@ -6641,6 +7243,7 @@
    "value": 200297.54610317945,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6652,6 +7255,7 @@
    "value": 201058.68415096402,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6663,6 +7267,7 @@
    "value": 201802.60497659445,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6674,6 +7279,7 @@
    "value": 202609.80542340875,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6685,6 +7291,7 @@
    "value": 203501.29058858752,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6696,6 +7303,7 @@
    "value": 204417.0512445569,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6707,6 +7315,7 @@
    "value": 205296.04370743036,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "healthy_start_vouchers",
@@ -6718,6 +7327,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6729,6 +7339,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6740,6 +7351,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6751,6 +7363,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6762,6 +7375,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6773,6 +7387,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6784,6 +7399,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "maternity_allowance",
@@ -6795,6 +7411,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6806,6 +7423,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6817,6 +7435,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6828,6 +7447,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6839,6 +7459,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6850,6 +7471,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6861,6 +7483,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "maternity_allowance",
@@ -6872,6 +7495,7 @@
    "value": 3318182317.450847,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6883,6 +7507,7 @@
    "value": 3407399609.1208797,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6894,6 +7519,7 @@
    "value": 3488407179.3860164,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6905,6 +7531,7 @@
    "value": 3572407800.478435,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6916,6 +7543,7 @@
    "value": 3659888978.871894,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6927,6 +7555,7 @@
    "value": 3749885904.2724175,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6938,6 +7567,7 @@
    "value": 3841330547.982543,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_maternity_pay",
@@ -6949,6 +7579,7 @@
    "value": 333845.906548053,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -6960,6 +7591,7 @@
    "value": 335114.53039878607,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -6971,6 +7603,7 @@
    "value": 336354.45804458857,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -6982,6 +7615,7 @@
    "value": 337699.85739299655,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -6993,6 +7627,7 @@
    "value": 339185.7411582172,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -7004,6 +7639,7 @@
    "value": 340712.0907050073,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -7015,6 +7651,7 @@
    "value": 342177.1517958939,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_maternity_pay",
@@ -7026,6 +7663,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7037,6 +7675,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7048,6 +7687,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7059,6 +7699,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7070,6 +7711,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7081,6 +7723,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7092,6 +7735,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_paternity_pay",
@@ -7103,6 +7747,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7114,6 +7759,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7125,6 +7771,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7136,6 +7783,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7147,6 +7795,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7158,6 +7807,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7169,6 +7819,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_paternity_pay",
@@ -7180,6 +7831,7 @@
    "value": 1129666049.2058818,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7191,6 +7843,7 @@
    "value": 1160039811.2081735,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7202,6 +7855,7 @@
    "value": 1187618628.8419445,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7213,6 +7867,7 @@
    "value": 1216216439.2552707,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7224,6 +7879,7 @@
    "value": 1245999166.4642668,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7235,6 +7891,7 @@
    "value": 1276638374.6988342,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7246,6 +7903,7 @@
    "value": 1307770469.3172994,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "statutory_sick_pay",
@@ -7257,6 +7915,7 @@
    "value": 181849.49628841877,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7268,6 +7927,7 @@
    "value": 182540.52988168597,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7279,6 +7939,7 @@
    "value": 183215.93420261145,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7290,6 +7951,7 @@
    "value": 183948.78862804174,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7301,6 +7963,7 @@
    "value": 184758.16779726744,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7312,6 +7975,7 @@
    "value": 185589.58406233788,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7323,6 +7987,7 @@
    "value": 186387.61916735768,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "statutory_sick_pay",
@@ -7334,6 +7999,7 @@
    "value": 13125578.55695486,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7345,6 +8011,7 @@
    "value": 13175456.283032894,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7356,6 +8023,7 @@
    "value": 13224205.684065819,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7367,6 +8035,7 @@
    "value": 13277101.755604148,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7378,6 +8047,7 @@
    "value": 13335521.275147796,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7389,6 +8059,7 @@
    "value": 13395531.273916364,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7400,6 +8071,7 @@
    "value": 13453131.819739938,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "ssmg",
@@ -7411,6 +8083,7 @@
    "value": 26251.15711390972,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7422,6 +8095,7 @@
    "value": 26350.91256606579,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7433,6 +8107,7 @@
    "value": 26448.411368131638,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7444,6 +8119,7 @@
    "value": 26554.203511208296,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7455,6 +8131,7 @@
    "value": 26671.04255029559,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7466,6 +8143,7 @@
    "value": 26791.062547832727,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7477,6 +8155,7 @@
    "value": 26906.263639479876,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "ssmg",
@@ -7488,6 +8167,7 @@
    "value": 670117436.1645457,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7499,6 +8179,7 @@
    "value": 688135183.9490275,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7510,6 +8191,7 @@
    "value": 704494923.9662163,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7521,6 +8203,7 @@
    "value": 721459099.2289677,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7532,6 +8215,7 @@
    "value": 739126209.3696653,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7543,6 +8227,7 @@
    "value": 757301345.0579464,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7554,6 +8239,7 @@
    "value": 775768909.9039654,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bsp",
@@ -7565,6 +8251,7 @@
    "value": 98107.17104572058,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7576,6 +8263,7 @@
    "value": 98479.98137193918,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7587,6 +8275,7 @@
    "value": 98844.35904490948,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7598,6 +8287,7 @@
    "value": 99239.73120433092,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7609,6 +8299,7 @@
    "value": 99676.38774478436,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7620,6 +8311,7 @@
    "value": 100124.9348872304,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7631,6 +8323,7 @@
    "value": 100555.47150915861,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bsp",
@@ -7642,6 +8335,7 @@
    "value": 551460799.5583543,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7653,6 +8347,7 @@
    "value": 556759454.765603,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7664,6 +8359,7 @@
    "value": 566094705.6608063,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7675,6 +8371,7 @@
    "value": 577814275.3520343,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7686,6 +8383,7 @@
    "value": 546986429.725085,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7697,6 +8395,7 @@
    "value": 566235601.269679,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7708,6 +8407,7 @@
    "value": 577475011.8886111,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "tax_free_childcare",
@@ -7719,6 +8419,7 @@
    "value": 1011592.7329891622,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7730,6 +8431,7 @@
    "value": 1021183.6429007053,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7741,6 +8443,7 @@
    "value": 1020334.1701015085,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7752,6 +8455,7 @@
    "value": 1023999.8023810685,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7763,6 +8467,7 @@
    "value": 972793.2253160179,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7774,6 +8479,7 @@
    "value": 980748.0028229207,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7785,6 +8491,7 @@
    "value": 980979.6002974808,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "tax_free_childcare",
@@ -7796,6 +8503,7 @@
    "value": 2648748217.184513,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7807,6 +8515,7 @@
    "value": 3074999356.8385277,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7818,6 +8527,7 @@
    "value": 3151701029.7253556,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7829,6 +8539,7 @@
    "value": 3235525477.42588,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7840,6 +8551,7 @@
    "value": 3310370308.099014,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7851,6 +8563,7 @@
    "value": 3398248782.2036104,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7862,6 +8575,7 @@
    "value": 3482394959.2131405,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "extended_childcare_entitlement",
@@ -7873,6 +8587,7 @@
    "value": 664320.1943173409,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7884,6 +8599,7 @@
    "value": 669802.4551296234,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7895,6 +8611,7 @@
    "value": 672223.7327985764,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7906,6 +8623,7 @@
    "value": 673895.0757799149,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7917,6 +8635,7 @@
    "value": 676376.3725852966,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7928,6 +8647,7 @@
    "value": 681117.3323864937,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7939,6 +8659,7 @@
    "value": 683408.1116919518,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "extended_childcare_entitlement",
@@ -7950,6 +8671,7 @@
    "value": 3266472521.328236,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -7961,6 +8683,7 @@
    "value": 3388720332.016673,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -7972,6 +8695,7 @@
    "value": 3479027407.998313,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -7983,6 +8707,7 @@
    "value": 3565630277.573733,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -7994,6 +8719,7 @@
    "value": 3653067234.422063,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -8005,6 +8731,7 @@
    "value": 3757717185.8182206,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -8016,6 +8743,7 @@
    "value": 3846294804.2724795,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "universal_childcare_entitlement",
@@ -8027,6 +8755,7 @@
    "value": 985445.4297113419,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8038,6 +8767,7 @@
    "value": 988718.9267745018,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8049,6 +8779,7 @@
    "value": 992135.8684687614,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8060,6 +8791,7 @@
    "value": 996884.7139797211,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8071,6 +8803,7 @@
    "value": 1001194.633936882,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8082,6 +8815,7 @@
    "value": 1010204.9373459816,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8093,6 +8827,7 @@
    "value": 1013771.0637845993,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "universal_childcare_entitlement",
@@ -8104,6 +8839,7 @@
    "value": 572024783.1285633,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8115,6 +8851,7 @@
    "value": 593721428.6371526,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8126,6 +8863,7 @@
    "value": 609623032.498304,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8137,6 +8875,7 @@
    "value": 624301765.4036878,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8148,6 +8887,7 @@
    "value": 639589086.6096659,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8159,6 +8899,7 @@
    "value": 655315201.2710408,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8170,6 +8911,7 @@
    "value": 664824494.3626773,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "targeted_childcare_entitlement",
@@ -8181,6 +8923,7 @@
    "value": 119291.62903356552,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8192,6 +8935,7 @@
    "value": 119744.94127082825,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8203,6 +8947,7 @@
    "value": 120188.00064563751,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8214,6 +8959,7 @@
    "value": 120668.74804401398,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8225,6 +8971,7 @@
    "value": 121199.69331502914,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8236,6 +8983,7 @@
    "value": 121745.09483098984,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8247,6 +8995,7 @@
    "value": 121100.23704528809,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "targeted_childcare_entitlement",
@@ -8258,6 +9007,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8269,6 +9019,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8280,6 +9031,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8291,6 +9043,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8302,6 +9055,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8313,6 +9067,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8324,6 +9079,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "care_to_learn",
@@ -8335,6 +9091,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8346,6 +9103,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8357,6 +9115,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8368,6 +9127,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8379,6 +9139,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8390,6 +9151,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8401,6 +9163,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "care_to_learn",
@@ -8412,6 +9175,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8423,6 +9187,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8434,6 +9199,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8445,6 +9211,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8456,6 +9223,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8467,6 +9235,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8478,6 +9247,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "childcare_grant",
@@ -8489,6 +9259,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8500,6 +9271,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8511,6 +9283,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8522,6 +9295,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8533,6 +9307,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8544,6 +9319,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8555,6 +9331,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "childcare_grant",
@@ -8566,6 +9343,7 @@
    "value": 199163916.0120163,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8577,6 +9355,7 @@
    "value": 199920745.4944954,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8588,6 +9367,7 @@
    "value": 200660457.07904816,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8599,6 +9379,7 @@
    "value": 201463089.27254868,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8610,6 +9391,7 @@
    "value": 202349531.5649414,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8621,6 +9403,7 @@
    "value": 203188174.47846603,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8632,6 +9415,7 @@
    "value": 204061882.82292938,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "parents_learning_allowance",
@@ -8643,6 +9427,7 @@
    "value": 98401.14427471161,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8654,6 +9439,7 @@
    "value": 98775.07188463211,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8665,6 +9451,7 @@
    "value": 99140.54203510284,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8676,6 +9463,7 @@
    "value": 99537.09944295883,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8687,6 +9475,7 @@
    "value": 99975.0650024414,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8698,6 +9487,7 @@
    "value": 100389.41426801682,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8709,6 +9499,7 @@
    "value": 100821.0883512497,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "parents_learning_allowance",
@@ -8720,6 +9511,7 @@
    "value": 62362242.98413515,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8731,6 +9523,7 @@
    "value": 62599222.553822994,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8742,6 +9535,7 @@
    "value": 44187742.20506668,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8753,6 +9547,7 @@
    "value": 44364490.80733061,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8764,6 +9559,7 @@
    "value": 44559696.51651859,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8775,6 +9571,7 @@
    "value": 44760217.169840336,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8786,6 +9583,7 @@
    "value": 44952685.864076614,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "adult_dependants_grant",
@@ -8797,6 +9595,7 @@
    "value": 17591.605919361115,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8808,6 +9607,7 @@
    "value": 17658.454881191254,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8819,6 +9619,7 @@
    "value": 12464.807392120361,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8830,6 +9631,7 @@
    "value": 12514.665954113007,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8841,6 +9643,7 @@
    "value": 12569.73103427887,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8852,6 +9655,7 @@
    "value": 12626.29539346695,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8863,6 +9667,7 @@
    "value": 12680.588396072388,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "adult_dependants_grant",
@@ -8874,6 +9679,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8885,6 +9691,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8896,6 +9703,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8907,6 +9715,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8918,6 +9727,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8929,6 +9739,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8940,6 +9751,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "travel_grant",
@@ -8951,6 +9763,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -8962,6 +9775,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -8973,6 +9787,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -8984,6 +9799,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -8995,6 +9811,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -9006,6 +9823,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -9017,6 +9835,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "travel_grant",
@@ -9028,6 +9847,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9039,6 +9859,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9050,6 +9871,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9061,6 +9883,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9072,6 +9895,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9083,6 +9907,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9094,6 +9919,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disabled_students_allowance",
@@ -9105,6 +9931,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9116,6 +9943,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9127,6 +9955,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9138,6 +9967,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9149,6 +9979,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9160,6 +9991,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9171,6 +10003,7 @@
    "value": null,
    "suppressed": true,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disabled_students_allowance",
@@ -9182,6 +10015,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9193,6 +10027,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9204,6 +10039,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9215,6 +10051,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9226,6 +10063,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9237,6 +10075,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9248,6 +10087,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "bursary_fund_16_to_19",
@@ -9259,6 +10099,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9270,6 +10111,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9281,6 +10123,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9292,6 +10135,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9303,6 +10147,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9314,6 +10159,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9325,6 +10171,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "bursary_fund_16_to_19",
@@ -9336,6 +10183,7 @@
    "value": 204681602159.08142,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9347,6 +10195,7 @@
    "value": 205459399297.22324,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9358,6 +10207,7 @@
    "value": 206219602604.32385,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9369,6 +10219,7 @@
    "value": 207044470471.60086,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9380,6 +10231,7 @@
    "value": 207955469002.00323,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9391,6 +10243,7 @@
    "value": 208891275075.5078,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9402,6 +10255,7 @@
    "value": 209789506836.96567,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "nhs_spending",
@@ -9413,6 +10267,7 @@
    "value": 23991604.347275984,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9424,6 +10279,7 @@
    "value": 24082773.488280036,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9435,6 +10291,7 @@
    "value": 24171879.76151417,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9446,6 +10303,7 @@
    "value": 24268565.8560597,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9457,6 +10315,7 @@
    "value": 24375348.2293824,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9468,6 +10327,7 @@
    "value": 24485037.725156102,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9479,6 +10339,7 @@
    "value": 24590323.320610803,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dfe_education_spending",
@@ -9490,6 +10351,7 @@
    "value": 25151126494.365833,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9501,6 +10363,7 @@
    "value": 25246701555.2342,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9512,6 +10375,7 @@
    "value": 25340114784.780163,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9523,6 +10387,7 @@
    "value": 25441473946.770885,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9534,6 +10399,7 @@
    "value": 25553416805.737003,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9545,6 +10411,7 @@
    "value": 25668407910.982876,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9556,6 +10423,7 @@
    "value": 25778782013.14279,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "dft_subsidy_spending",
@@ -9567,6 +10435,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9578,6 +10447,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9589,6 +10459,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9600,6 +10471,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9611,6 +10483,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9622,6 +10495,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9633,6 +10507,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "cost_of_living_support_payment",
@@ -9644,6 +10519,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9655,6 +10531,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9666,6 +10543,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9677,6 +10555,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9688,6 +10567,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9699,6 +10579,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9710,6 +10591,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "cost_of_living_support_payment",
@@ -9721,6 +10603,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9732,6 +10615,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9743,6 +10627,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9754,6 +10639,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9765,6 +10651,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9776,6 +10663,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9787,6 +10675,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "energy_bills_rebate",
@@ -9798,6 +10687,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9809,6 +10699,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9820,6 +10711,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9831,6 +10723,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9842,6 +10735,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9853,6 +10747,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9864,6 +10759,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "energy_bills_rebate",
@@ -9875,6 +10771,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9886,6 +10783,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9897,6 +10795,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9908,6 +10807,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9919,6 +10819,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9930,6 +10831,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9941,6 +10843,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "epg_subsidy",
@@ -9952,6 +10855,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -9963,6 +10867,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -9974,6 +10879,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -9985,6 +10891,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -9996,6 +10903,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -10007,6 +10915,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -10018,6 +10927,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "epg_subsidy",
@@ -10029,6 +10939,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10040,6 +10951,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10051,6 +10963,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10062,6 +10975,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10073,6 +10987,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10084,6 +10999,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10095,6 +11011,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "basic_income",
@@ -10106,6 +11023,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10117,6 +11035,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10128,6 +11047,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10139,6 +11059,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10150,6 +11071,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10161,6 +11083,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10172,6 +11095,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "basic_income",
@@ -10183,6 +11107,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10194,6 +11119,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10205,6 +11131,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10216,6 +11143,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10227,6 +11155,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10238,6 +11167,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10249,6 +11179,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "disability_basic_income",
@@ -10260,6 +11191,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10271,6 +11203,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10282,6 +11215,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10293,6 +11227,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10304,6 +11239,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10315,6 +11251,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10326,6 +11263,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "caseload",
    "partition": "disability_basic_income",
@@ -10337,6 +11275,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10348,6 +11287,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10359,6 +11299,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10370,6 +11311,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10381,6 +11323,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10392,6 +11335,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10403,6 +11347,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "spending",
    "partition": "other_public_spending_budget_change",
@@ -10414,6 +11359,7 @@
    "value": 3130000159.912464,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10425,6 +11371,7 @@
    "value": 3130000023.6063724,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10436,6 +11383,7 @@
    "value": 3129999836.909186,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10447,6 +11395,7 @@
    "value": 3129999962.584343,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10458,6 +11407,7 @@
    "value": 3129999544.0565424,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10469,6 +11419,7 @@
    "value": 3129999895.007397,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10480,6 +11431,7 @@
    "value": 3129999484.877694,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "double_count",
    "partition": null,
@@ -10491,6 +11443,7 @@
    "value": 969745776128.1699,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10502,6 +11455,7 @@
    "value": 1011784948712.7561,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10513,6 +11467,7 @@
    "value": 1050610465294.2213,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10524,6 +11479,7 @@
    "value": 1085614034747.1652,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10535,6 +11491,7 @@
    "value": 1124265122009.6616,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10546,6 +11503,7 @@
    "value": 1163453498626.6191,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10557,6 +11515,7 @@
    "value": 1206982869582.7024,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10568,6 +11527,7 @@
    "value": 503977430092.485,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10579,6 +11539,7 @@
    "value": 531055850973.52136,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10590,6 +11551,7 @@
    "value": 557277774892.158,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10601,6 +11563,7 @@
    "value": 579764609886.5848,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10612,6 +11575,7 @@
    "value": 603325541929.8473,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10623,6 +11587,7 @@
    "value": 628508152120.9532,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10634,6 +11599,7 @@
    "value": 656263699478.5581,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10645,6 +11611,7 @@
    "value": 496150814427.7457,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10656,6 +11623,7 @@
    "value": 522932377454.86273,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10667,6 +11635,7 @@
    "value": 548928559890.4607,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10678,6 +11647,7 @@
    "value": 570722062751.3651,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10689,6 +11659,7 @@
    "value": 594044368863.5272,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10700,6 +11671,7 @@
    "value": 618963456079.3445,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10711,6 +11683,7 @@
    "value": 646366448427.6294,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10724,6 +11697,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10737,6 +11713,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10750,6 +11729,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10763,6 +11745,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10776,6 +11761,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10789,6 +11777,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10802,6 +11793,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10815,6 +11809,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10828,6 +11825,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10841,6 +11841,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10854,6 +11857,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10867,6 +11873,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10880,6 +11889,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10893,6 +11905,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -10904,6 +11919,7 @@
    "value": 966615777128.9729,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10915,6 +11931,7 @@
    "value": 1008654948197.3245,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10926,6 +11943,7 @@
    "value": 1047480466355.038,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10937,6 +11955,7 @@
    "value": 1082484034898.3741,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10948,6 +11967,7 @@
    "value": 1121135120971.1062,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10959,6 +11979,7 @@
    "value": 1160323499762.114,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10970,6 +11991,7 @@
    "value": 1203852872416.6934,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10983,6 +12005,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -10996,6 +12021,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11009,6 +12037,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11022,6 +12053,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11035,6 +12069,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11048,6 +12085,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11061,6 +12101,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11074,6 +12117,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11087,6 +12133,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11100,6 +12149,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11113,6 +12165,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11126,6 +12181,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11139,6 +12197,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11152,6 +12213,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11163,6 +12227,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11174,6 +12239,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11185,6 +12251,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11196,6 +12263,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11207,6 +12275,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11218,6 +12287,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11229,6 +12299,7 @@
    "value": 0.0,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "balance",
    "partition": null,
@@ -11242,6 +12313,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11255,6 +12329,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11268,6 +12345,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11281,6 +12361,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11294,6 +12377,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11307,6 +12393,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11320,6 +12409,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": -1
+   },
    "unit": "gbp",
    "kind": "model_total",
    "partition": null,
@@ -11331,6 +12423,7 @@
    "value": 1657055494245.5037,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11342,6 +12435,7 @@
    "value": 1719245701089.3281,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11353,6 +12447,7 @@
    "value": 1771683231648.2764,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11364,6 +12459,7 @@
    "value": 1821985672731.2063,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11375,6 +12471,7 @@
    "value": 1887412879505.8608,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11386,6 +12483,7 @@
    "value": 1945587770944.968,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11397,6 +12495,7 @@
    "value": 2017368706417.267,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11410,6 +12509,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11423,6 +12525,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11436,6 +12541,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11449,6 +12557,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11462,6 +12573,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11475,6 +12589,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11488,6 +12605,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11499,6 +12619,7 @@
    "value": 1468438454639.119,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11510,6 +12631,7 @@
    "value": 1515139365275.6355,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11521,6 +12643,7 @@
    "value": 1547358223256.206,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11532,6 +12655,7 @@
    "value": 1580410096999.486,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11543,6 +12667,7 @@
    "value": 1613429021347.468,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11554,6 +12679,7 @@
    "value": 1647838190515.2617,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11565,6 +12691,7 @@
    "value": 1697900004504.373,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "household_total",
    "partition": null,
@@ -11576,6 +12703,7 @@
    "value": 0.158961068989031,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11587,6 +12715,7 @@
    "value": 0.149417048095037,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11598,6 +12727,7 @@
    "value": 0.1551359605887892,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11609,6 +12739,7 @@
    "value": 0.15590985583220196,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11620,6 +12751,7 @@
    "value": 0.15717923007921353,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11631,6 +12763,7 @@
    "value": 0.1610142002033216,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11642,6 +12775,7 @@
    "value": 0.1599545027297433,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11653,6 +12787,7 @@
    "value": 11050012.62085329,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11664,6 +12799,7 @@
    "value": 10426039.302517518,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11675,6 +12811,7 @@
    "value": 10865147.24560164,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11686,6 +12823,7 @@
    "value": 10963024.831684813,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11697,6 +12835,7 @@
    "value": 11100912.898740932,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11708,6 +12847,7 @@
    "value": 11422934.10709335,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11719,6 +12859,7 @@
    "value": 11396550.62013276,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11730,6 +12871,7 @@
    "value": 0.2372510378251411,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11741,6 +12883,7 @@
    "value": 0.20852661548421755,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11752,6 +12895,7 @@
    "value": 0.21671681039197135,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11763,6 +12907,7 @@
    "value": 0.21457714000706526,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11774,6 +12919,7 @@
    "value": 0.21642597560772944,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11785,6 +12931,7 @@
    "value": 0.2217104975392767,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11796,6 +12943,7 @@
    "value": 0.22078118293404653,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11807,6 +12955,7 @@
    "value": 3559375.146835327,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11818,6 +12967,7 @@
    "value": 3140323.1707639247,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11829,6 +12979,7 @@
    "value": 3275739.6749524027,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11840,6 +12991,7 @@
    "value": 3256371.3432342857,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11851,6 +13003,7 @@
    "value": 3298880.366600305,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11862,6 +13015,7 @@
    "value": 3394637.414582446,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11873,6 +13027,7 @@
    "value": 3394944.311651394,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11884,6 +13039,7 @@
    "value": 0.13767748825105397,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11895,6 +13051,7 @@
    "value": 0.13372106552488075,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11906,6 +13063,7 @@
    "value": 0.13989204520959575,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11917,6 +13075,7 @@
    "value": 0.14124164361087443,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11928,6 +13087,7 @@
    "value": 0.14248707378049913,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11939,6 +13099,7 @@
    "value": 0.14658630153368837,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11950,6 +13111,7 @@
    "value": 0.14525417694146392,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -11961,6 +13123,7 @@
    "value": 5863952.6221417785,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11972,6 +13135,7 @@
    "value": 5736660.92677407,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11983,6 +13147,7 @@
    "value": 6072487.460049972,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -11994,6 +13159,7 @@
    "value": 6178484.984416798,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12005,6 +13171,7 @@
    "value": 6260390.306578115,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12016,6 +13183,7 @@
    "value": 6469478.6622083485,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12027,6 +13195,7 @@
    "value": 6438252.252475888,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12038,6 +13207,7 @@
    "value": 0.13647330334302774,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12049,6 +13219,7 @@
    "value": 0.13107228723131284,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12060,6 +13231,7 @@
    "value": 0.13176164489560352,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12071,6 +13243,7 @@
    "value": 0.13408989504529978,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12082,6 +13255,7 @@
    "value": 0.13467956142673865,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12093,6 +13267,7 @@
    "value": 0.13556998964969896,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12104,6 +13279,7 @@
    "value": 0.13538234298373342,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12115,6 +13291,7 @@
    "value": 1626684.8518761843,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12126,6 +13303,7 @@
    "value": 1549055.204979524,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12137,6 +13315,7 @@
    "value": 1516920.1105992645,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12148,6 +13327,7 @@
    "value": 1528168.5040337294,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12159,6 +13339,7 @@
    "value": 1541642.2255625129,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12170,6 +13351,7 @@
    "value": 1558818.0303025544,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12181,6 +13363,7 @@
    "value": 1563354.056005478,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12192,6 +13375,7 @@
    "value": 0.20913249144654364,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12203,6 +13387,7 @@
    "value": 0.20368321654160576,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12214,6 +13399,7 @@
    "value": 0.2099396779334123,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12225,6 +13411,7 @@
    "value": 0.21265695145642433,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12236,6 +13423,7 @@
    "value": 0.2154006487190125,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12247,6 +13435,7 @@
    "value": 0.22356054596434546,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12258,6 +13447,7 @@
    "value": 0.223770468364186,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12269,6 +13459,7 @@
    "value": 14537626.631551296,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12280,6 +13471,7 @@
    "value": 14212630.00441049,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12291,6 +13483,7 @@
    "value": 14703396.329152241,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12302,6 +13495,7 @@
    "value": 14953278.142699987,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12313,6 +13507,7 @@
    "value": 15212848.660455883,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12324,6 +13519,7 @@
    "value": 15860199.797730953,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12335,6 +13531,7 @@
    "value": 15943355.307177946,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12346,6 +13543,7 @@
    "value": 0.3176647822027365,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12357,6 +13555,7 @@
    "value": 0.29976792277040976,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12368,6 +13567,7 @@
    "value": 0.3075246154957757,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12379,6 +13579,7 @@
    "value": 0.31040394928891696,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12390,6 +13591,7 @@
    "value": 0.31404388184177656,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12401,6 +13603,7 @@
    "value": 0.32925032071219956,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12412,6 +13615,7 @@
    "value": 0.3295364201437651,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12423,6 +13627,7 @@
    "value": 4765787.92304638,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12434,6 +13639,7 @@
    "value": 4514378.90334405,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12445,6 +13651,7 @@
    "value": 4648326.921118781,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12456,6 +13663,7 @@
    "value": 4710616.076148167,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12467,6 +13675,7 @@
    "value": 4786824.655172229,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12478,6 +13687,7 @@
    "value": 5041193.222052559,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12489,6 +13699,7 @@
    "value": 5067269.683862701,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12500,6 +13711,7 @@
    "value": 0.19431403398519395,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12511,6 +13723,7 @@
    "value": 0.19237286661348602,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12522,6 +13735,7 @@
    "value": 0.1997992793069061,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12533,6 +13747,7 @@
    "value": 0.20238185535311953,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12544,6 +13759,7 @@
    "value": 0.20530273277647584,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12555,6 +13771,7 @@
    "value": 0.2131128866367783,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12566,6 +13783,7 @@
    "value": 0.21322897588420822,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12577,6 +13795,7 @@
    "value": 8276213.515957296,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12588,6 +13807,7 @@
    "value": 8252835.130660608,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12599,6 +13819,7 @@
    "value": 8672963.61491029,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12610,6 +13831,7 @@
    "value": 8853006.963460386,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12621,6 +13843,7 @@
    "value": 9020293.589352593,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12632,6 +13855,7 @@
    "value": 9405580.591863185,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12643,6 +13867,7 @@
    "value": 9451170.101861268,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12654,6 +13879,7 @@
    "value": 0.12547784554248842,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12665,6 +13891,7 @@
    "value": 0.12230292156970884,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12676,6 +13903,7 @@
    "value": 0.12005149872375881,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12687,6 +13915,7 @@
    "value": 0.12193596873043704,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12698,6 +13927,7 @@
    "value": 0.12280615616424372,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12709,6 +13939,7 @@
    "value": 0.1229252820223357,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12720,6 +13951,7 @@
    "value": 0.12339393057336441,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12731,6 +13963,7 @@
    "value": 1495625.1925476193,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12742,6 +13975,7 @@
    "value": 1445415.970405832,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12753,6 +13987,7 @@
    "value": 1382105.7931231707,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12764,6 +13999,7 @@
    "value": 1389655.1030914336,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12775,6 +14011,7 @@
    "value": 1405730.415931061,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12786,6 +14023,7 @@
    "value": 1413425.983815208,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12797,6 +14035,7 @@
    "value": 1424915.5214539766,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12808,6 +14047,7 @@
    "value": 0.16996315965340555,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12819,6 +14059,7 @@
    "value": 0.1641757039106901,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12830,6 +14071,7 @@
    "value": 0.1658306356282735,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12841,6 +14083,7 @@
    "value": 0.16675706960047298,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12852,6 +14095,7 @@
    "value": 0.16818506457390087,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12863,6 +14107,7 @@
    "value": 0.16603686894151898,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12874,6 +14119,7 @@
    "value": 0.16939429823668872,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12885,6 +14131,7 @@
    "value": 11814811.457891181,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12896,6 +14143,7 @@
    "value": 11455870.419837251,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12907,6 +14155,7 @@
    "value": 11614162.616421178,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12918,6 +14167,7 @@
    "value": 11725762.204902157,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12929,6 +14179,7 @@
    "value": 11878209.046851024,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12940,6 +14191,7 @@
    "value": 11779260.530264333,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12951,6 +14203,7 @@
    "value": 12069123.79252024,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -12962,6 +14215,7 @@
    "value": 0.2576548985094404,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12973,6 +14227,7 @@
    "value": 0.2349385317072657,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12984,6 +14239,7 @@
    "value": 0.23473844147435505,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -12995,6 +14251,7 @@
    "value": 0.23360704801218143,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13006,6 +14263,7 @@
    "value": 0.23495351453647773,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13017,6 +14275,7 @@
    "value": 0.23174222961978033,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13028,6 +14287,7 @@
    "value": 0.23914597293246234,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13039,6 +14299,7 @@
    "value": 3865485.4816306233,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13050,6 +14311,7 @@
    "value": 3538075.5262937695,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13061,6 +14323,7 @@
    "value": 3548142.041142389,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13072,6 +14335,7 @@
    "value": 3545164.6745751947,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13083,6 +14347,7 @@
    "value": 3581287.015071422,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13094,6 +14359,7 @@
    "value": 3548234.530783549,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13105,6 +14371,7 @@
    "value": 3677339.0271395296,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13116,6 +14383,7 @@
    "value": 0.14512498963363443,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13127,6 +14395,7 @@
    "value": 0.14359366405754964,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13138,6 +14407,7 @@
    "value": 0.1475713897931732,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13149,6 +14419,7 @@
    "value": 0.1494918942688663,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13160,6 +14431,7 @@
    "value": 0.1516084128453753,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13171,6 +14443,7 @@
    "value": 0.1503840561165627,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13182,6 +14455,7 @@
    "value": 0.15254973464975796,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13193,6 +14467,7 @@
    "value": 6181156.224673748,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13204,6 +14479,7 @@
    "value": 6160197.413159236,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13215,6 +14491,7 @@
    "value": 6405835.3899862915,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13226,6 +14503,7 @@
    "value": 6539384.56406565,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13237,6 +14515,7 @@
    "value": 6661150.467831269,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13248,6 +14527,7 @@
    "value": 6637089.76898399,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13259,6 +14539,7 @@
    "value": 6761620.8594070375,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13270,6 +14551,7 @@
    "value": 0.14834340320557673,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13281,6 +14563,7 @@
    "value": 0.14871795468967855,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13292,6 +14575,7 @@
    "value": 0.14420583478126237,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13303,6 +14587,7 @@
    "value": 0.14400903683858882,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13314,6 +14599,7 @@
    "value": 0.14290280401894626,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13325,6 +14611,7 @@
    "value": 0.1386242101836538,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13336,6 +14623,7 @@
    "value": 0.14116789999709253,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13347,6 +14635,7 @@
    "value": 1768169.7515868098,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13358,6 +14647,7 @@
    "value": 1757597.4803842455,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13369,6 +14659,7 @@
    "value": 1660185.1852924973,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13380,6 +14671,7 @@
    "value": 1641212.9662613124,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13391,6 +14683,7 @@
    "value": 1635771.5639483333,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13402,6 +14695,7 @@
    "value": 1593936.230496794,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13413,6 +14707,7 @@
    "value": 1630163.9059736729,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13424,6 +14719,7 @@
    "value": 0.21456512996755925,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13435,6 +14731,7 @@
    "value": 0.2108568153025047,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13446,6 +14743,7 @@
    "value": 0.21280995156860974,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13457,6 +14755,7 @@
    "value": 0.2141820445617756,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13468,6 +14767,7 @@
    "value": 0.2155949209344568,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13479,6 +14779,7 @@
    "value": 0.21996997492343381,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13490,6 +14791,7 @@
    "value": 0.2227237561956704,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13501,6 +14803,7 @@
    "value": 14915270.822066262,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13512,6 +14815,7 @@
    "value": 14713190.171909258,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13523,6 +14827,7 @@
    "value": 14904419.64807345,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13534,6 +14839,7 @@
    "value": 15060517.248883188,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13545,6 +14851,7 @@
    "value": 15226569.296071708,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13556,6 +14863,7 @@
    "value": 15605471.6038488,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13567,6 +14875,7 @@
    "value": 15868778.424316749,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13578,6 +14887,7 @@
    "value": 0.32573092950864546,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13589,6 +14899,7 @@
    "value": 0.3129215499802995,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13600,6 +14911,7 @@
    "value": 0.31080197766773193,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13611,6 +14923,7 @@
    "value": 0.3112443481181635,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13622,6 +14935,7 @@
    "value": 0.31435135617461696,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13633,6 +14947,7 @@
    "value": 0.32341397660487087,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13644,6 +14959,7 @@
    "value": 0.32841073439755847,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13655,6 +14971,7 @@
    "value": 4886800.85733974,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13666,6 +14983,7 @@
    "value": 4712466.999728724,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13677,6 +14995,7 @@
    "value": 4697865.234627768,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13688,6 +15007,7 @@
    "value": 4723369.767731324,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13699,6 +15019,7 @@
    "value": 4791511.343251109,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13710,6 +15031,7 @@
    "value": 4951832.22069715,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13721,6 +15043,7 @@
    "value": 5049960.054618016,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13732,6 +15055,7 @@
    "value": 0.19817681755370278,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13743,6 +15067,7 @@
    "value": 0.19800752646020686,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13754,6 +15079,7 @@
    "value": 0.2018228258946827,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13765,6 +15091,7 @@
    "value": 0.20314734474442595,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13776,6 +15103,7 @@
    "value": 0.2054474903629614,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13787,6 +15115,7 @@
    "value": 0.21027795561183132,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13798,6 +15127,7 @@
    "value": 0.2126635701601802,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13809,6 +15139,7 @@
    "value": 8440736.998503834,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13820,6 +15151,7 @@
    "value": 8494563.18488653,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13831,6 +15163,7 @@
    "value": 8760802.499964043,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13842,6 +15175,7 @@
    "value": 8886492.58844325,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13853,6 +15187,7 @@
    "value": 9026653.738152012,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13864,6 +15199,7 @@
    "value": 9280462.995042503,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13875,6 +15211,7 @@
    "value": 9426109.034751624,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13886,6 +15223,7 @@
    "value": 0.133205373171771,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13897,6 +15235,7 @@
    "value": 0.12744273660248256,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13908,6 +15247,7 @@
    "value": 0.125579883146286,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13919,6 +15259,7 @@
    "value": 0.12728842519447406,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13930,6 +15271,7 @@
    "value": 0.12303974216451169,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13941,6 +15283,7 @@
    "value": 0.119424785385011,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13952,6 +15295,7 @@
    "value": 0.12060495966103543,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "rate",
    "kind": "poverty",
    "partition": null,
@@ -13963,6 +15307,7 @@
    "value": 1587732.9662226886,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13974,6 +15319,7 @@
    "value": 1506159.9872940034,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13985,6 +15331,7 @@
    "value": 1445751.9134816378,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -13996,6 +15343,7 @@
    "value": 1450654.8927086145,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -14007,6 +15355,7 @@
    "value": 1408404.2146685869,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -14018,6 +15367,7 @@
    "value": 1373176.3881091475,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -14029,6 +15379,7 @@
    "value": 1392709.3349471092,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "count",
    "kind": "poverty_count",
    "partition": null,
@@ -14040,6 +15391,7 @@
    "value": 0.3077487914075191,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14051,6 +15403,7 @@
    "value": 0.3054631654461407,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14062,6 +15415,7 @@
    "value": 0.3069197698442653,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14073,6 +15427,7 @@
    "value": 0.3077757166797609,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14084,6 +15439,7 @@
    "value": 0.3082329014779346,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14095,6 +15451,7 @@
    "value": 0.3099891970371004,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14106,6 +15463,7 @@
    "value": 0.3110144570254967,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "index",
    "kind": "inequality",
    "partition": null,
@@ -14119,6 +15477,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14132,6 +15493,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14145,6 +15509,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14158,6 +15525,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14171,6 +15541,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14184,6 +15557,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14197,6 +15573,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14210,6 +15589,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14223,6 +15605,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14236,6 +15621,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14249,6 +15637,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14262,6 +15653,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14275,6 +15669,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14288,6 +15685,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14301,6 +15701,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14314,6 +15717,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14327,6 +15733,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14340,6 +15749,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14353,6 +15765,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14366,6 +15781,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14379,6 +15797,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14392,6 +15813,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14405,6 +15829,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14418,6 +15845,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14431,6 +15861,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14444,6 +15877,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14457,6 +15893,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14470,6 +15909,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14483,6 +15925,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14496,6 +15941,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14509,6 +15957,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14522,6 +15973,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14535,6 +15989,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14548,6 +16005,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14561,6 +16021,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14574,6 +16037,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14587,6 +16053,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14600,6 +16069,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14613,6 +16085,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14626,6 +16101,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14639,6 +16117,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14652,6 +16133,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14665,6 +16149,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14678,6 +16165,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14691,6 +16181,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14704,6 +16197,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14717,6 +16213,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14730,6 +16229,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14743,6 +16245,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14756,6 +16261,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14769,6 +16277,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14782,6 +16293,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14795,6 +16309,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14808,6 +16325,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14821,6 +16341,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14834,6 +16357,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14847,6 +16373,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14860,6 +16389,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14873,6 +16405,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14886,6 +16421,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14899,6 +16437,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14912,6 +16453,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14925,6 +16469,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14938,6 +16485,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14951,6 +16501,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14964,6 +16517,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14977,6 +16533,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -14990,6 +16549,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -15003,6 +16565,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -15016,6 +16581,9 @@
    "excludes": [
     "spending.disabled_students_allowance"
    ],
+   "exclude_signs": {
+    "spending.disabled_students_allowance": 1
+   },
    "unit": "gbp_household",
    "kind": "decile",
    "partition": null,
@@ -15027,6 +16595,7 @@
    "value": 6222687308.254578,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15038,6 +16607,7 @@
    "value": 6508759614.741272,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15049,6 +16619,7 @@
    "value": 6714986157.079834,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15060,6 +16631,7 @@
    "value": 6913272334.154663,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15071,6 +16643,7 @@
    "value": 7118288039.173706,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15082,6 +16655,7 @@
    "value": 7356266082.489136,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15093,6 +16667,7 @@
    "value": 7633159472.480713,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15104,6 +16679,7 @@
    "value": 6366582048.682007,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15115,6 +16691,7 @@
    "value": 6660786957.415405,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15126,6 +16703,7 @@
    "value": 6876392706.334412,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15137,6 +16715,7 @@
    "value": 7081815371.239807,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15148,6 +16727,7 @@
    "value": 7290951197.121887,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15159,6 +16739,7 @@
    "value": 7531692335.065491,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15170,6 +16751,7 @@
    "value": 7809724834.753845,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15181,6 +16763,7 @@
    "value": 3548582094.3916626,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15192,6 +16775,7 @@
    "value": 3840615655.607727,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15203,6 +16787,7 @@
    "value": 4076238853.5632935,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15214,6 +16799,7 @@
    "value": 4299497163.4904785,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15225,6 +16811,7 @@
    "value": 4571859488.912842,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15236,6 +16823,7 @@
    "value": 4855874568.11499,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15247,6 +16835,7 @@
    "value": 5076062695.494751,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15258,6 +16847,7 @@
    "value": 3554390535.588806,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15269,6 +16859,7 @@
    "value": 3848232118.605835,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15280,6 +16871,7 @@
    "value": 4084949832.10614,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15291,6 +16883,7 @@
    "value": 4309251584.078491,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15302,6 +16895,7 @@
    "value": 4582787139.6779785,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15313,6 +16907,7 @@
    "value": 4868223711.304871,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15324,6 +16919,7 @@
    "value": 5089139733.0060425,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15335,6 +16931,7 @@
    "value": -3822246893.5978394,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15346,6 +16943,7 @@
    "value": -3970099818.8598022,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15357,6 +16955,7 @@
    "value": -4052308604.757263,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15368,6 +16967,7 @@
    "value": -4101725729.7006836,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15379,6 +16979,7 @@
    "value": -4183390396.729248,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15390,6 +16991,7 @@
    "value": -4290067047.536621,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15401,6 +17003,7 @@
    "value": -2026458045.3624268,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15412,6 +17015,7 @@
    "value": -3954063036.4473877,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15423,6 +17027,7 @@
    "value": -4117335693.9852905,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15434,6 +17039,7 @@
    "value": -4209427536.251709,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15445,6 +17051,7 @@
    "value": -4261098604.1522827,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15456,6 +17063,7 @@
    "value": -4343355439.515015,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15467,6 +17075,7 @@
    "value": -4452755767.392151,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15478,6 +17087,7 @@
    "value": -1780300034.5704956,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15489,6 +17099,7 @@
    "value": -1978301080.5203857,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15500,6 +17111,7 @@
    "value": -1746066703.213379,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15511,6 +17123,7 @@
    "value": -1629668073.130188,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15522,6 +17135,7 @@
    "value": -1530858259.5943604,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15533,6 +17147,7 @@
    "value": -1428323970.4534912,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15544,6 +17159,7 @@
    "value": -1325576053.7683105,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15555,6 +17171,7 @@
    "value": -1219354845.269043,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15566,6 +17183,7 @@
    "value": 2330588637.038988,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15577,6 +17195,7 @@
    "value": 2141486725.888443,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15588,6 +17207,7 @@
    "value": 2023775956.2239304,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15599,6 +17219,7 @@
    "value": 1920161279.352703,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15610,6 +17231,7 @@
    "value": 1813779891.1509056,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15621,6 +17243,7 @@
    "value": 1704712527.6125221,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15632,6 +17255,7 @@
    "value": 1591189257.2969856,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15643,6 +17267,7 @@
    "value": -20527842919.80768,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15654,6 +17279,7 @@
    "value": -21100518260.464355,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15665,6 +17291,7 @@
    "value": -21383710367.08246,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15676,6 +17303,7 @@
    "value": -21736411484.46698,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15687,6 +17315,7 @@
    "value": -21748894837.86438,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15698,6 +17327,7 @@
    "value": -21876938936.24524,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15709,6 +17339,7 @@
    "value": -22330952654.634155,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15720,6 +17351,7 @@
    "value": 20519585447.911682,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15731,6 +17363,7 @@
    "value": 21090575767.801956,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15742,6 +17375,7 @@
    "value": 21373214076.36197,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15753,6 +17387,7 @@
    "value": 21725838011.858963,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15764,6 +17399,7 @@
    "value": 21742175658.693848,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15775,6 +17411,7 @@
    "value": 21868780192.75914,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15786,6 +17423,7 @@
    "value": 22322933920.91278,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15797,6 +17435,7 @@
    "value": 11064401706.310059,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15808,6 +17447,7 @@
    "value": 11510324242.230225,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15819,6 +17459,7 @@
    "value": 11834108533.458801,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15830,6 +17471,7 @@
    "value": 12138956950.555908,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15841,6 +17483,7 @@
    "value": 12464179087.056396,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15852,6 +17495,7 @@
    "value": 12812306848.333618,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15863,6 +17507,7 @@
    "value": 13289675311.854004,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15874,6 +17519,7 @@
    "value": 11329957618.034607,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15885,6 +17531,7 @@
    "value": 11791691034.516708,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15896,6 +17543,7 @@
    "value": 12126516761.37503,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15907,6 +17555,7 @@
    "value": 12442433003.455788,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15918,6 +17567,7 @@
    "value": 12770326792.025597,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15929,6 +17579,7 @@
    "value": 13120133297.630943,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15940,6 +17591,7 @@
    "value": 13607405556.501923,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -15951,6 +17603,7 @@
    "value": 30863021596.225952,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15962,6 +17615,7 @@
    "value": 31692844228.266296,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15973,6 +17627,7 @@
    "value": 32446311527.309143,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15984,6 +17639,7 @@
    "value": 33227617036.870483,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -15995,6 +17651,7 @@
    "value": 34041293064.6344,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16006,6 +17663,7 @@
    "value": 34878374451.18152,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16017,6 +17675,7 @@
    "value": 35728921387.40991,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16028,6 +17687,7 @@
    "value": 30863018576.160828,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16039,6 +17699,7 @@
    "value": 31692847105.070984,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16050,6 +17711,7 @@
    "value": 32446312252.777954,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16061,6 +17723,7 @@
    "value": 33227616036.71393,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16072,6 +17735,7 @@
    "value": 34041297530.920654,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16083,6 +17747,7 @@
    "value": 34878372560.67273,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16094,6 +17759,7 @@
    "value": 35728918405.68787,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16105,6 +17771,7 @@
    "value": 2798505716.117798,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16116,6 +17783,7 @@
    "value": 3023336469.8702393,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16127,6 +17795,7 @@
    "value": 3213071953.8966064,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16138,6 +17807,7 @@
    "value": 3394779601.3947754,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16149,6 +17819,7 @@
    "value": 3594508773.6256104,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16160,6 +17831,7 @@
    "value": 3822543323.427368,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16171,6 +17843,7 @@
    "value": 4125743282.83667,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16182,6 +17855,7 @@
    "value": 2798504994.492798,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16193,6 +17867,7 @@
    "value": 3023336460.849365,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16204,6 +17879,7 @@
    "value": 3213071862.152466,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16215,6 +17891,7 @@
    "value": 3394780483.9908447,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16226,6 +17903,7 @@
    "value": 3594509097.7042236,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16237,6 +17915,7 @@
    "value": 3822542242.9839478,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16248,6 +17927,7 @@
    "value": 4125743186.885071,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16259,6 +17939,7 @@
    "value": -3038583641.996826,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16270,6 +17951,7 @@
    "value": -3168138984.6657715,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16281,6 +17963,7 @@
    "value": -3225527730.8588867,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16292,6 +17975,7 @@
    "value": -3282105874.806885,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16303,6 +17987,7 @@
    "value": -3307346412.4144287,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16314,6 +17999,7 @@
    "value": -3331520951.5113525,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16325,6 +18011,7 @@
    "value": -3373553161.4073486,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16336,6 +18023,7 @@
    "value": 3041523709.2714844,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16347,6 +18035,7 @@
    "value": 3171636381.1340485,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16358,6 +18047,7 @@
    "value": 3226364754.786072,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16369,6 +18059,7 @@
    "value": 3282674243.09433,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16380,6 +18071,7 @@
    "value": 3312220329.68396,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16391,6 +18083,7 @@
    "value": 3337058613.859558,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16402,6 +18095,7 @@
    "value": 3377518834.7556,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16413,6 +18107,7 @@
    "value": -8927432756.88562,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16424,6 +18119,7 @@
    "value": -9142939686.93689,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16435,6 +18131,7 @@
    "value": -9062725924.750671,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16446,6 +18143,7 @@
    "value": -9114943836.081665,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16457,6 +18155,7 @@
    "value": -9306907164.58667,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16468,6 +18167,7 @@
    "value": -9548783655.451294,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16479,6 +18179,7 @@
    "value": -9816145928.907349,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform",
    "partition": null,
@@ -16490,6 +18191,7 @@
    "value": 12250304093.31047,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16501,6 +18203,7 @@
    "value": 12711504064.702667,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16512,6 +18215,7 @@
    "value": 12828062954.26825,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16523,6 +18227,7 @@
    "value": 13020927023.28334,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16534,6 +18239,7 @@
    "value": 13405169512.460327,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16545,6 +18251,7 @@
    "value": 13802157356.131042,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
@@ -16556,6 +18263,7 @@
    "value": 14208043135.872528,
    "suppressed": false,
    "excludes": [],
+   "exclude_signs": {},
    "unit": "gbp",
    "kind": "reform_target",
    "partition": null,
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index aafd090b..b3448ceb 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1398,13 +1398,17 @@ def test_a_worse_row_never_improves_the_gate(data, worse, section):
 }
 
 
+#: The small-cell fields every row of the pinned tool's report carries.
+PUBLISHED = {"suppressed": False, "excludes": [], "exclude_signs": {}}
+
+
 def _report(values, **extra):
     return {
         "status": "ok",
         "metrics_version": "m1",
         "partition_version": "p1",
         "metrics": [
-            {"metric_id": mid, "year": year, "value": value, "kind": kind}
+            {"metric_id": mid, "year": year, "value": value, "kind": kind, **PUBLISHED}
             for (mid, year, kind), value in values.items()
         ],
         # Every real report carries checks; one always passes here.
@@ -1448,8 +1452,13 @@ def test_metric_comparison_rules():
     warned = _report(
         BASE, identities=[{"identity_id": "inert:alcohol_duty", "status": "warn"}]
     )
-    status, _, evidence = compare_metric_reports(warned, _report(BASE), BOUNDS)
+    # A warning the previous report also gave is recorded; any other is new
+    # (the tool's new_warning), including one from a check it did not run.
+    status, _, evidence = compare_metric_reports(warned, warned, BOUNDS)
     assert status == "pass" and evidence["warn_identities"] == ["inert:alcohol_duty"]
+    status, _, evidence = compare_metric_reports(warned, _report(BASE), BOUNDS)
+    assert status == "needs_review"
+    assert evidence["new_warnings"] == ["inert:alcohol_duty"]
 
 
 def test_reports_that_measure_nothing_fail():
@@ -1582,6 +1591,16 @@ def _checks(**statuses):
             {"inert__tobacco_duty": "pass"},
             "needs_review",
         ),
+        (
+            {"inert__tobacco_duty": "warn"},
+            {"inert__tobacco_duty": "skipped"},
+            "needs_review",
+        ),
+        (
+            {"inert__tobacco_duty": "warn"},
+            {"inert__tobacco_duty": "fail"},
+            "needs_review",
+        ),
     ],
 )
 def test_check_classification(candidate, previous, status):
@@ -1654,7 +1673,9 @@ def candidate(scale):
 
 
 def _cells(rows):
-    """A report from ``(metric_id, year, kind, value, suppressed, excludes)`` rows."""
+    """A report from ``(metric_id, year, kind, value, suppressed, excludes)``
+    rows, with an optional seventh item giving ``exclude_signs`` (by default
+    +1 for each excluded figure)."""
 
     report = _report({})
     report["metrics"] = [
@@ -1665,8 +1686,11 @@ def _cells(rows):
             "value": value,
             "suppressed": suppressed,
             "excludes": list(excludes),
+            "exclude_signs": dict(signs[0])
+            if signs
+            else {excluded: 1 for excluded in excludes},
         }
-        for metric_id, year, kind, value, suppressed, excludes in rows
+        for metric_id, year, kind, value, suppressed, excludes, *signs in rows
     ]
     return report
 
@@ -1724,46 +1748,159 @@ def test_a_figure_suppressed_on_one_side_is_withheld(candidate, previous, reason
     withheld = {
         (row["metric_id"], row["reason"]) for row in evidence["withheld_changes"]
     }
-    assert (DSA, reason) in withheld
-    # The total's sides leave out different figures, so it is withheld too,
-    # even though its two published values are equal.
-    assert (
-        "model.gov_spending",
-        "the reports leave out different suppressed figures",
-    ) in withheld
+    assert withheld == {(DSA, reason)}
+    # The total is lined up: the side that publishes the head takes it out.
+    assert evidence["lined_up_totals"] == ["model.gov_spending 2027"]
     assert evidence["moves_beyond_bounds"] == []
 
 
+def _one_sided(kind, sign, *, rest_c, rest_p, head_p=2.0e10, metric="total"):
+    """A total over a head suppressed in the candidate and published in the
+    previous report, which it holds there with ``sign``. Values are synthetic."""
+
+    candidate = _cells(
+        [
+            (DSA, 2027, "spending", None, True, ()),
+            (metric, 2027, kind, rest_c, False, (DSA,), {DSA: sign}),
+        ]
+    )
+    previous = _cells(
+        [
+            (DSA, 2027, "spending", head_p, False, ()),
+            (metric, 2027, kind, rest_p + sign * head_p, False, (), {}),
+        ]
+    )
+    return candidate, previous
+
+
+@pytest.mark.parametrize("sign", [1, -1])
 @pytest.mark.parametrize(
-    "kind", ["model_total", "balance", "decile", "household_total"]
+    ("kind", "metric"),
+    [
+        ("model_total", "model.gov_spending"),
+        ("balance", "balance.balance"),
+        ("household_total", "household.household_net_income"),
+    ],
 )
-@pytest.mark.parametrize("candidate_value", [5.4e11, 5.4e11 + 1.0, 9.9e11])
-def test_totals_with_different_exclusions_are_never_lined_up(kind, candidate_value):
-    """The report lists excluded ids without their signs, so no section,
-    additive or not, gets a computed change: it is withheld for review."""
-
-    def side(value, excludes):
-        return _cells(
-            [
-                ("income_tax", 2027, "receipt", 3.0e11, False, ()),
-                (DSA, 2027, "spending", None, True, ()),
-                ("other_head", 2027, "spending", None, True, ()),
-                ("total", 2027, kind, value, False, excludes),
-            ]
+def test_additive_totals_are_lined_up_from_published_figures(kind, metric, sign):
+    """As the tool's compare._aligned: the previous side takes out the head
+    only the candidate excludes, at its own published value and the
+    candidate's sign. The head (£20bn, synthetic) is four times the bound,
+    so comparing the totals as published would flag it."""
+
+    same, previous = _one_sided(kind, sign, rest_c=5.0e11, rest_p=5.0e11, metric=metric)
+    status, _, evidence = compare_metric_reports(same, previous, BOUNDS)
+    assert status == "needs_review"  # the head itself is withheld
+    assert evidence["lined_up_totals"] == [f"{metric} 2027"]
+    assert evidence["moves_beyond_bounds"] == []
+    assert [row["metric_id"] for row in evidence["withheld_changes"]] == [DSA]
+    moved, previous = _one_sided(
+        kind, sign, rest_c=5.3e11, rest_p=5.0e11, metric=metric
+    )
+    (move,) = compare_metric_reports(moved, previous, BOUNDS)[2]["moves_beyond_bounds"]
+    assert move["metric_id"] == metric and move["lined_up_without"] == [DSA]
+    assert move["change"] == pytest.approx(3.0e10)
+    # The published levels are recorded, never a lined-up one.
+    assert move["previous"] == 5.0e11 + sign * 2.0e10
+    assert move["candidate"] == 5.3e11
+    # Lined up the other way round: the candidate publishes the head.
+    status, _, evidence = compare_metric_reports(previous, moved, BOUNDS)
+    assert evidence["lined_up_totals"] == [f"{metric} 2027"]
+    assert evidence["moves_beyond_bounds"][0]["change"] == pytest.approx(-3.0e10)
+
+
+def test_the_relative_bound_is_taken_on_the_previous_published_total():
+    """W3: the tool flags with threshold.exceeded(b, b + delta), b the base's
+    published level. Published previous £5.0bn (with the head £2.0bn),
+    lined-up previous £3.0bn: 2% is £100m on the first, £60m on the second."""
+
+    bounds = {"default": {"relative": 0.02, "absolute": 0.0}}
+
+    def change(by):
+        return _one_sided(
+            "model_total", 1, rest_c=3.0e9 + by, rest_p=3.0e9, head_p=2.0e9
         )
 
-    candidate = side(candidate_value, (DSA, "other_head"))
-    previous = side(5.4e11, (DSA,))
+    within, previous = change(8.0e7)
+    assert (
+        compare_metric_reports(within, previous, bounds)[2]["moves_beyond_bounds"] == []
+    )
+    beyond, previous = change(1.2e8)
+    (move,) = compare_metric_reports(beyond, previous, bounds)[2]["moves_beyond_bounds"]
+    assert move["threshold"] == pytest.approx(1.0e8)
+
+
+@pytest.mark.parametrize(
+    ("kind", "metric"),
+    [
+        ("decile", "deciles.mean_income.3"),
+        ("household_total", "household.hbai_household_net_income"),
+        ("caseload", "caseloads.child_benefit"),
+        ("poverty", "poverty.relative_bhc"),
+    ],
+)
+def test_other_totals_with_different_exclusions_are_withheld(kind, metric):
+    """Decile means and the HBAI total (reset at zero) are not sums of
+    heads, so different exclusions cannot be lined up: withheld."""
+
+    candidate, previous = _one_sided(
+        kind, 1, rest_c=5.0e11, rest_p=5.0e11, metric=metric
+    )
     status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
     assert status == "needs_review", summary
-    (row,) = evidence["withheld_changes"]
-    assert row == {
-        "metric_id": "total",
+    assert {
+        "metric_id": metric,
         "year": 2027,
         "reason": "the reports leave out different suppressed figures",
-        "candidate_excludes": sorted([DSA, "other_head"]),
-        "previous_excludes": [DSA],
-    }
+        "candidate_excludes": [DSA],
+        "previous_excludes": [],
+    } in evidence["withheld_changes"]
+    assert evidence["lined_up_totals"] == evidence["moves_beyond_bounds"] == []
+
+
+def test_totals_that_cannot_be_lined_up_are_withheld():
+    other = "spending.other_head"
+    # The head the previous side would take out is not in its report.
+    candidate, previous = _one_sided("model_total", 1, rest_c=5.0e11, rest_p=5.0e11)
+    previous["metrics"] = [
+        row for row in previous["metrics"] if row["metric_id"] != DSA
+    ]
+    evidence = compare_metric_reports(candidate, previous, BOUNDS)[2]
+    assert evidence["withheld_changes"][-1]["reason"] == (
+        "the reports leave out different suppressed figures, and one needed "
+        "to line them up is not published"
+    )
+    assert evidence["lined_up_totals"] == []
+    # A figure both sides exclude enters with different signs (the partition
+    # changed): the two totals are not the same sum.
+    candidate = _cells(
+        [
+            (DSA, 2027, "spending", None, True, ()),
+            (other, 2027, "spending", None, True, ()),
+            ("total", 2027, "balance", 5.0e11, False, (DSA, other), {DSA: 1, other: 1}),
+        ]
+    )
+    previous = _cells(
+        [
+            (DSA, 2027, "spending", None, True, ()),
+            (other, 2027, "spending", 1.0e9, False, ()),
+            ("total", 2027, "balance", 5.0e11, False, (DSA,), {DSA: -1}),
+        ]
+    )
+    evidence = compare_metric_reports(candidate, previous, BOUNDS)[2]
+    assert evidence["withheld_changes"][-1]["reason"] == (
+        "a figure both reports leave out enters their totals with different signs"
+    )
+    # Signs that do not match the exclusions fail the report, and nothing
+    # is lined up from them.
+    candidate, previous = _one_sided("model_total", 1, rest_c=5.0e11, rest_p=5.0e11)
+    candidate["metrics"][1]["exclude_signs"] = {}
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "fail" and "exclude_signs that are not +1 or -1" in summary
+    assert evidence["withheld_changes"][-1]["reason"] == (
+        "the reports leave out different suppressed figures, without the "
+        "signs needed to line them up"
+    )
     assert evidence["moves_beyond_bounds"] == []
 
 
@@ -1807,6 +1944,67 @@ def test_totals_at_equal_exclusions_compare_numerically():
             lambda rows: rows[2].update(year=2028),
             "totals excluding a figure it does not suppress",
         ),
+        (
+            lambda rows: rows[0].pop("exclude_signs"),
+            "rows without the small-cell fields",
+        ),
+        (
+            lambda rows: [row.pop("suppressed") for row in rows],
+            "rows without the small-cell fields",
+        ),
+        (
+            lambda rows: rows[0].update(year="2027"),
+            "metric rows whose year is not an integer",
+        ),
+        (
+            lambda rows: rows[2].update(exclude_signs={DSA: 2}),
+            "exclude_signs that are not +1 or -1 for exactly its excludes",
+        ),
+        (
+            lambda rows: rows[2].update(exclude_signs={DSA: True}),
+            "exclude_signs that are not +1 or -1",
+        ),
+        (
+            lambda rows: rows[2].update(exclude_signs={DSA: 1, "income_tax": -1}),
+            "exclude_signs that are not +1 or -1",
+        ),
+        (
+            lambda rows: rows[2].update(exclude_signs=[DSA]),
+            "exclude_signs that are not +1 or -1",
+        ),
+        (
+            # W3's measure_year suppresses the caseload with its head, even
+            # when the caseload is zero.
+            lambda rows: rows.append(
+                {
+                    "metric_id": "caseloads.disabled_students_allowance",
+                    "year": 2027,
+                    "kind": "caseload",
+                    "value": 0.0,
+                    **PUBLISHED,
+                }
+            ),
+            "caseloads not suppressed together with their spending head: "
+            "caseloads.disabled_students_allowance 2027",
+        ),
+        (
+            lambda rows: (
+                rows[1].update(value=2.0e6, suppressed=False),
+                rows[2].update(excludes=[], exclude_signs={}),
+                rows.append(
+                    {
+                        "metric_id": "caseloads.disabled_students_allowance",
+                        "year": 2027,
+                        "kind": "caseload",
+                        "value": None,
+                        "suppressed": True,
+                        "excludes": [],
+                        "exclude_signs": {},
+                    }
+                ),
+            ),
+            "caseloads not suppressed together with their spending head",
+        ),
     ],
     ids=[
         "suppressed with a value",
@@ -1815,6 +2013,15 @@ def test_totals_at_equal_exclusions_compare_numerically():
         "excludes a number",
         "excludes an unsuppressed figure",
         "excludes a figure suppressed in another year",
+        "no exclude_signs",
+        "no suppressed flags (a tool from before suppression)",
+        "year as text",
+        "sign of 2",
+        "sign True",
+        "signs for a figure not excluded",
+        "signs not a map",
+        "zero caseload published beside a suppressed head",
+        "caseload suppressed beside a published head",
     ],
 )
 @pytest.mark.parametrize("side", ["candidate", "previous"])
@@ -1836,6 +2043,37 @@ def test_a_boolean_metric_value_is_not_a_number():
     assert status == "fail" and "non-finite values" in summary
 
 
+@pytest.mark.parametrize("side", ["candidate", "previous"])
+def test_a_repeated_check_cannot_decide_the_comparison(side):
+    """A second copy of a check must not turn a regression into a carried
+    failure (supp-r1 review): a repeated id fails the report."""
+
+    regression = (
+        _report(BASE, identities=[{"identity_id": "sign:x", "status": "fail"}]),
+        _report(BASE, identities=[{"identity_id": "sign:x", "status": "pass"}]),
+    )
+    assert compare_metric_reports(*regression, BOUNDS)[0] == "fail"
+    candidate, previous = regression
+    repeated = previous if side == "previous" else candidate
+    repeated["identities"].append(
+        {"identity_id": "sign:x", "status": "fail" if side == "previous" else "pass"}
+    )
+    status, summary, _ = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "fail" and f"the {side} report repeats checks: sign:x" in summary
+
+
+@pytest.mark.parametrize("status", ["INVALID", None, "PASS"])
+def test_an_unknown_status_in_the_previous_report_is_not_a_pass(status):
+    """It decides new warnings and regressions, so it fails like the
+    candidate's would (supp-r1 review)."""
+
+    candidate = _report(BASE, identities=[{"identity_id": "inert:x", "status": "warn"}])
+    previous = _report(BASE, identities=[{"identity_id": "inert:x", "status": status}])
+    result = compare_metric_reports(candidate, previous, BOUNDS)
+    assert result[0] == "fail"
+    assert "the previous report has checks with an unknown status: inert:x" in result[1]
+
+
 @pytest.mark.parametrize(
     ("check", "previous", "status", "newly", "hard"),
     [
@@ -1917,6 +2155,80 @@ def side(choices):
         }
 
 
+_SIDE = st.tuples(
+    st.sampled_from(["published", "suppressed"]),
+    st.floats(min_value=1.0e8, max_value=5.0e10),
+    st.floats(min_value=-0.5, max_value=0.5, allow_nan=False),
+)
+
+
+@settings(max_examples=400, deadline=None)
+@given(
+    candidate_side=_SIDE,
+    previous_side=_SIDE,
+    sign=st.sampled_from([1, -1]),
+    kind=st.sampled_from(["model_total", "balance", "decile"]),
+)
+def test_lining_up_against_a_reference(candidate_side, previous_side, sign, kind):
+    """Differential against the tool's rule, stated independently: a head
+    published or suppressed on each side, a total that holds it with
+    ``sign`` where it is published and excludes it where it is not."""
+
+    def side(state, head, change):
+        rest = 4.0e11 * (1 + change)
+        if state == "suppressed":
+            rows = [
+                (DSA, 2027, "spending", None, True, ()),
+                ("total", 2027, kind, rest, False, (DSA,), {DSA: sign}),
+            ]
+        else:
+            rows = [
+                (DSA, 2027, "spending", head, False, ()),
+                ("total", 2027, kind, rest + sign * head, False, (), {}),
+            ]
+        return _cells(rows), rows
+
+    candidate, c_rows = side(*candidate_side)
+    previous, p_rows = side(*previous_side)
+    (c_state, c_head, _), (p_state, p_head, _) = candidate_side, previous_side
+    c_total, p_total = c_rows[1][3], p_rows[1][3]
+    review, lined_up, change = False, False, None
+    if c_state == p_state == "published":
+        head_threshold = max(0.02 * abs(p_head), 5e8)
+        review |= abs(c_head - p_head) > head_threshold
+        change = c_total - p_total
+    elif c_state == p_state == "suppressed":
+        change = c_total - p_total
+    else:
+        review = True  # the head is withheld
+        if kind in ("model_total", "balance"):
+            lined_up = True
+            # The side that publishes the head takes it out with the sign
+            # the other side records, exactly as the gate computes it.
+            if c_state == "published":
+                change = (c_total - sign * c_head) - p_total
+            else:
+                change = c_total - (p_total - sign * p_head)
+    if change is not None and abs(change) > max(0.02 * abs(p_total), 5e8):
+        review = True
+    status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == ("needs_review" if review else "pass"), summary
+    assert evidence["lined_up_totals"] == (["total 2027"] if lined_up else [])
+    total_moves = [
+        m for m in evidence["moves_beyond_bounds"] if m["metric_id"] == "total"
+    ]
+    if total_moves:
+        assert total_moves[0]["change"] == change
+    for row in evidence["withheld_changes"]:
+        assert set(row) <= {
+            "metric_id",
+            "year",
+            "reason",
+            "candidate_excludes",
+            "previous_excludes",
+        }
+
+
 @settings(max_examples=200, deadline=None)
 @given(
     rows=st.lists(
@@ -2719,20 +3031,92 @@ def test_a_withheld_year_never_excuses_a_failure():
     assert reform_responsiveness_gate(unmarked)[0].status == "error"
 
 
-@settings(max_examples=100, deadline=None)
+def test_a_suppressed_reform_target_with_a_value_is_never_used_or_recorded():
+    """supp-r1 review: a target marked suppressed but carrying a value (a
+    synthetic one here) must not pass, and its value never reaches the
+    evidence."""
+
+    report = _responsive_report()
+    for row in report["metrics"]:
+        if row["metric_id"] == f"reform_targets.{UC_ALLOWANCE}" and row["year"] == 2027:
+            row["suppressed"] = True  # keeps its (passing) value
+    result, evidence = reform_responsiveness_gate(report)
+    assert result.status == "error"
+    assert (
+        f"suppressed reform targets carry a value: reform_targets.{UC_ALLOWANCE} 2027"
+        in (result.summary)
+    )
+    rows = {row["id"]: row for row in evidence["reforms"]}
+    assert rows[UC_ALLOWANCE]["target_changes"]["2027"] is None
+    assert rows[UC_ALLOWANCE]["withheld_years"] == []
+
+
+@pytest.mark.parametrize("what", ["target", "reform_runs", "responsive"])
+def test_a_repeated_reform_row_cannot_decide_responsiveness(what):
+    report = _responsive_report()
+    if what == "target":
+        row = next(
+            r
+            for r in report["metrics"]
+            if r["metric_id"] == f"reform_targets.{UC_ALLOWANCE}"
+        )
+        report["metrics"].append({**row, "value": 0.0})
+        repeated = f"reform_targets.{UC_ALLOWANCE} {row['year']}"
+    else:
+        check = f"{what}:{UC_ALLOWANCE}"
+        report["identities"].append({"identity_id": check, "status": "pass"})
+        repeated = check
+    result = reform_responsiveness_gate(report)[0]
+    assert (
+        result.status == "error" and f"the report repeats {repeated}" in result.summary
+    )
+
+
+def test_a_boolean_reform_target_is_not_a_number():
+    """supp-r1 mutant M21: True must not count as a change of 1."""
+
+    reform = {**_standard_reforms()[0], "minimum": 0.5}
+    report = {
+        "status": "ok",
+        "years": [2027],
+        "metrics": [
+            {"metric_id": f"reform_targets.{reform['id']}", "year": 2027, "value": True}
+        ],
+        "identities": [
+            {"identity_id": f"reform_runs:{reform['id']}", "status": "pass"},
+            {"identity_id": f"responsive:{reform['id']}", "status": "pass"},
+        ],
+    }
+    from policyengine.provenance.uk_candidate import reform_responsiveness
+
+    result = reform_responsiveness(
+        report=report, standard_reforms=[reform], years=[2027]
+    )[0]
+    assert result.status == "error" and "do not meet the minimum" in result.summary
+
+
+@settings(max_examples=150, deadline=None)
 @given(
     withheld=st.sets(st.sampled_from(RESPONSE_YEARS)),
     scale=st.floats(min_value=-3.0, max_value=6.0),
 )
 def test_withholding_never_improves_responsiveness(withheld, scale):
     """Monotone in information: withholding years never turns a fail or an
-    error into a pass, and never passes at all."""
+    error into a pass, and never passes at all. Only the State Pension
+    reform varies; the other nine respond, so its own verdict decides."""
 
     order = {"pass": 0, "needs_review": 1, "fail": 2, "error": 2}
-    full = reform_responsiveness_gate(_responsive_report(scale=scale))[0].status
+    pension = next(r for r in _standard_reforms() if r["id"] == STATE_PENSION)
+    sign = 1.0 if pension["direction"] == "up" else -1.0
+    overrides = {
+        (STATE_PENSION, year): sign * pension["minimum"] * scale
+        for year in RESPONSE_YEARS
+    }
+    full = reform_responsiveness_gate(_responsive_report(overrides=overrides))[0].status
     hidden = reform_responsiveness_gate(
-        _withhold(_responsive_report(scale=scale), STATE_PENSION, withheld)
+        _withhold(_responsive_report(overrides=overrides), STATE_PENSION, withheld)
     )[0].status
+    assert full == ("pass" if scale >= 1.0 else "fail")
     if withheld:
         assert hidden != "pass"
     assert order[hidden] >= order[full]
@@ -2869,6 +3253,92 @@ def test_the_real_report_suppresses_its_small_cells():
     assert "totals excluding a figure it does not suppress" in summary
 
 
+def test_the_real_report_gives_each_excluded_figure_its_sign():
+    """At 1191ac5a4 Disabled Students' Allowance enters the spending totals,
+    household benefits and household net income at +1, and the two balances
+    at -1."""
+
+    signs = {
+        row["metric_id"]: row["exclude_signs"]
+        for row in _real_report()["metrics"]
+        if row["excludes"] and row["year"] == 2027
+    }
+    dsa = "spending.disabled_students_allowance"
+    assert {metric for metric, sign in signs.items() if sign == {dsa: -1}} == {
+        "model.gov_balance",
+        "balance.balance",
+    }
+    assert all(sign in ({dsa: 1}, {dsa: -1}) for sign in signs.values())
+
+
+def test_a_head_published_in_the_previous_pair_lines_up_on_the_real_report():
+    """A previous pair that published Disabled Students' Allowance in
+    2027-28 (a synthetic £5m and 1,000 claimants, not data): its totals hold
+    it, the candidate's are rebuilt without it. The six additive totals line
+    up exactly; the head, its caseload and the ten decile means are
+    withheld."""
+
+    candidate, previous = _real_report(), _real_report()
+    dsa = "spending.disabled_students_allowance"
+    synthetic = {dsa: 5.0e6, "caseloads.disabled_students_allowance": 1.0e3}
+    for row in previous["metrics"]:
+        if row["year"] != 2027:
+            continue
+        if row["metric_id"] in synthetic:
+            row.update(value=synthetic[row["metric_id"]], suppressed=False)
+        elif row["excludes"]:
+            row["value"] += row["exclude_signs"][dsa] * synthetic[dsa]
+            row.update(excludes=[], exclude_signs={})
+    status, summary, evidence = compare_metric_reports(
+        candidate, previous, _real_bounds()
+    )
+    assert status == "needs_review", summary
+    assert sorted(evidence["lined_up_totals"]) == sorted(
+        f"{metric} 2027"
+        for metric in (
+            "balance.balance",
+            "balance.spending",
+            "household.household_net_income",
+            "model.gov_balance",
+            "model.gov_spending",
+            "model.household_benefits",
+        )
+    )
+    withheld = sorted(row["metric_id"] for row in evidence["withheld_changes"])
+    assert withheld == sorted(
+        [dsa, "caseloads.disabled_students_allowance"]
+        + [f"deciles.mean_income.{decile}" for decile in range(1, 11)]
+    )
+    assert evidence["moves_beyond_bounds"] == []
+
+
+def test_only_a_well_formed_report_is_published_to_the_ledger():
+    """The ledger is public: a report that breaks the small-cell format is
+    replaced by its digest and problems (supp-r1 review)."""
+
+    from policyengine.provenance.uk_candidate import publishable_metrics_report
+
+    report = _real_report()
+    assert publishable_metrics_report(report) == report
+    marker = 123456789.25  # synthetic
+    leaked = _real_report()
+    for row in leaked["metrics"]:
+        if row["metric_id"] == "spending.disabled_students_allowance":
+            row["value"] = marker
+    published = publishable_metrics_report(leaked)
+    assert set(published) == {"withheld", "report_sha256", "problems"}
+    assert "suppressed figures with a value" in published["problems"][0]
+    assert str(marker) not in json.dumps(published)
+    # A report from a tool that predates suppression is not published either.
+    old = _real_report()
+    for row in old["metrics"]:
+        for field in ("suppressed", "excludes", "exclude_signs"):
+            row.pop(field)
+        row["value"] = row["value"] if row["value"] is not None else marker
+    assert "withheld" in publishable_metrics_report(old)
+    assert str(marker) not in json.dumps(publishable_metrics_report(old))
+
+
 def test_a_real_failure_that_spread_to_a_new_year_has_worsened():
     """Scope-based no-worsening on the tool's real failing_scopes."""
 
diff --git a/tests/test_uk_candidate_metric_baselines.py b/tests/test_uk_candidate_metric_baselines.py
index 38f087e4..b55fc15e 100644
--- a/tests/test_uk_candidate_metric_baselines.py
+++ b/tests/test_uk_candidate_metric_baselines.py
@@ -9,6 +9,10 @@
 BOUNDS = {"default": {"relative": 0.02, "absolute": 5e8}}
 
 
+#: The small-cell fields every row of the pinned tool's report carries.
+PUBLISHED = {"suppressed": False, "excludes": [], "exclude_signs": {}}
+
+
 def _report():
     return {
         "status": "ok",
@@ -20,12 +24,14 @@ def _report():
                 "year": 2027,
                 "kind": "receipt",
                 "value": 3e11,
+                **PUBLISHED,
             },
             {
                 "metric_id": "relative_poverty",
                 "year": 2027,
                 "kind": "poverty",
                 "value": 0.17,
+                **PUBLISHED,
             },
         ],
         "identities": [{"identity_id": "weights:household", "status": "pass"}],
@@ -554,10 +560,10 @@ def test_unpinned_previous_baselines_are_incomplete(tmp_path, missing):
     assert result.status == "unavailable"
 
 
-@pytest.mark.parametrize("identity_mismatch", [False, True])
-def test_metric_orchestration_uses_the_verified_previous_dataset_before_computing(
-    tmp_path, monkeypatch, identity_mismatch
-):
+def _orchestrate_metrics(tmp_path, monkeypatch, metrics, identity_mismatch=False):
+    """Run ``run_candidate_gates`` with only the metrics gate and ``metrics``
+    standing in for ``run_metrics_report``; ``(results, evidence)``."""
+
     import json
     from pathlib import Path
     from types import SimpleNamespace
@@ -573,7 +579,6 @@ def test_metric_orchestration_uses_the_verified_previous_dataset_before_computin
             Path(__file__).parents[1] / "src/policyengine/data/qualification/uk.json"
         ).read_text()
     )
-    calls = []
     monkeypatch.setattr(uk_candidate, "_previous_pair_pins", lambda *args: previous)
     monkeypatch.setattr(
         uk_candidate, "previous_pair_python", lambda *args: "certified-previous-python"
@@ -600,6 +605,48 @@ def only_metrics(gates):
         return [result], {"metrics_review": evidence}
 
     monkeypatch.setattr(uk_candidate, "run_gates", only_metrics)
+    monkeypatch.setattr(uk_candidate, "run_metrics_report", metrics)
+    return uk_candidate.run_candidate_gates(
+        SimpleNamespace(pair=make_pair()),
+        HARNESS,
+        config=config,
+        work_dir=tmp_path,
+        previous_certificate=previous,
+        ledger_root=None,
+    )
+
+
+def test_a_malformed_metrics_report_is_not_written_to_the_ledger(tmp_path, monkeypatch):
+    """The attempt's evidence goes to a public ledger branch: a report that
+    breaks the small-cell format is kept only as its digest and problems."""
+
+    import json
+
+    marker = 987654321.5  # synthetic
+
+    def metrics(python, vendor, **settings):
+        report = _report()
+        report["dataset_path"] = str(settings["dataset_path"])
+        if settings["label"] == "candidate":
+            report["metrics"][0].update(value=marker, suppressed=True)
+        return report
+
+    results, evidence = _orchestrate_metrics(tmp_path, monkeypatch, metrics)
+    assert results[0].status == "fail"
+    assert set(evidence["metrics_report_candidate"]) == {
+        "withheld",
+        "report_sha256",
+        "problems",
+    }
+    assert str(marker) not in json.dumps(evidence["metrics_report_candidate"])
+    assert evidence["metrics_report_previous"]["metrics"] == _report()["metrics"]
+
+
+@pytest.mark.parametrize("identity_mismatch", [False, True])
+def test_metric_orchestration_uses_the_verified_previous_dataset_before_computing(
+    tmp_path, monkeypatch, identity_mismatch
+):
+    calls = []
 
     def metrics(python, vendor, **settings):
         calls.append((python, settings))
@@ -609,15 +656,8 @@ def metrics(python, vendor, **settings):
             report["metrics"][0]["value"] = 1e12
         return report
 
-    monkeypatch.setattr(uk_candidate, "run_metrics_report", metrics)
-    results, _ = uk_candidate.run_candidate_gates(
-        SimpleNamespace(pair=make_pair()),
-        HARNESS,
-        config=config,
-        work_dir=tmp_path,
-        previous_certificate=previous,
-        ledger_root=None,
-    )
+    results, _ = _orchestrate_metrics(tmp_path, monkeypatch, metrics, identity_mismatch)
+    previous_path = tmp_path / "certified-previous.h5"
     if identity_mismatch:
         assert results[0].status == "unavailable"
         assert calls == [], (

From 1bb9b3a472582233dee73d5130230815cbf86ded Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 02:21:47 -0400
Subject: [PATCH 39/45] Suppress small counts in published contract evidence;
 close round 10

Round 10 of #574 found that the reform contract fixture committed in
a416230a publishes two counts from fewer than 10 records of the survey
data (people whose 2027 tax fell: 4; UC payments that fell: 1), and
that the ledger would publish the same report shape.

- The reform contract gate now hashes and publishes
  publishable_contract_report: population rows, the only ones computed
  on the dataset, have every count from 1 to 9 in their detail replaced
  by "fewer than 10" (the metrics tool's privacy.py rule). The details'
  report_sha256 is of that published report too; a digest of the full
  report would let anyone recover a suppressed count by trying nine
  values. The gate still judges the report as returned; no rule reads
  detail.
- The fixture's two counts are suppressed the same way (three rows
  each), noted in its README; the unused 1.0.0 run on 2.126.8 is
  removed. The history is covered by cos d1613.
- Round 10 lows: the released run is also gated with its assertion ids
  removed (kills the three surviving resolution mutants); the run-level
  row test substitutes the runner's whole row; README nits fixed.
- Tests: the published evidence on the real run, and a Hypothesis
  property that no count from 1 to 9 survives publication while
  everything else is unchanged.

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                      |    2 +-
 src/policyengine/provenance/uk_candidate.py   |   52 +-
 tests/fixtures/uk_contract/README.md          |    9 +-
 .../uk_contract/full_allpass_uk_2.126.8.json  | 3665 -----------------
 .../uk_contract/full_released_uk_2.130.1.json |   12 +-
 tests/test_uk_candidate_gates.py              |  134 +-
 6 files changed, 181 insertions(+), 3693 deletions(-)
 delete mode 100644 tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index 7aa73eb5..d2bf789d 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. The ledger also never publishes a count from fewer than 10 records in the reform contract's population checks. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index e8acc9de..b1b52c13 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1249,10 +1249,13 @@ def reform_contract(
         and {status: summary.get(status, 0) for status in _CONTRACT_STATUSES} != counts
     ):
         malformed.append("the report's summary disagrees with its rows")
+    published = publishable_contract_report(report)
     details = {
         "contract_id": report.get("contract_id"),
         "contract_version": report.get("contract_version"),
-        "report_sha256": evidence_sha256(report),
+        # The digest of what is published: one of the full report would let
+        # anyone recover a suppressed count by trying the nine values.
+        "report_sha256": evidence_sha256(published),
         "counts": counts,
         "pending": pending,
         "unsupported": unsupported,
@@ -1263,12 +1266,12 @@ def reform_contract(
             "reform_contract",
             "fail",
             f"{len(failures)} contract row(s) failed: {', '.join(failures[:8])}",
-            report,
+            published,
             details,
         )
     if malformed:
         return _result(
-            "reform_contract", "error", "; ".join(malformed[:8]), report, details
+            "reform_contract", "error", "; ".join(malformed[:8]), published, details
         )
     return _result(
         "reform_contract",
@@ -1278,11 +1281,52 @@ def reform_contract(
         + (f"; {len(pending)} pending a methodology call" if pending else "")
         + (f"; {len(unsupported)} unsupported by design" if unsupported else "")
         + ".",
-        report,
+        published,
         details,
     )
 
 
+#: The metrics tool's small-cell rule (``privacy.py`` in policyengine-uk's
+#: aggregate-impact tool): a count of 1 to 9 units from the dataset is never
+#: published, and is written as this text instead.
+SUPPRESSED_COUNT = "fewer than 10"
+
+
+def _suppress_small_counts(value: Any) -> Any:
+    """``value`` with every integer count from 1 to 9, at any depth, replaced."""
+
+    if isinstance(value, bool):
+        return value
+    if isinstance(value, int) and 0 < value < 10:
+        return SUPPRESSED_COUNT
+    if isinstance(value, Mapping):
+        return {key: _suppress_small_counts(item) for key, item in value.items()}
+    if isinstance(value, list):
+        return [_suppress_small_counts(item) for item in value]
+    return value
+
+
+def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
+    """The reform contract report as the qualification ledger publishes it.
+
+    The ledger is a branch of a public repository. Case and property rows
+    come from synthetic households, but population rows are computed on the
+    dataset, so a count of 1 to 9 in their ``detail`` (people whose tax fell,
+    payments that went down) is replaced by ``SUPPRESSED_COUNT``. The gate
+    judges the report as the runner returned it; no rule reads ``detail``.
+    """
+
+    published = dict(report)
+    if isinstance(report.get("population"), list):
+        published["population"] = [
+            {**row, "detail": _suppress_small_counts(row.get("detail"))}
+            if isinstance(row, Mapping)
+            else row
+            for row in report["population"]
+        ]
+    return published
+
+
 # --- 9. Metrics review ---------------------------------------------------------
 
 
diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index 3948b597..b3997b0b 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -5,8 +5,11 @@ Real reports from the UK Budget reform contract runner (workstream W1,
 run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate_gates.py` read them.
 
 - `pinned_uk_2.125.1_defects.json`: every case on policyengine-uk 2.125.1, the pinned model at the time, with `max_examples=2` and no dataset. The 66 failures and 35 errors are the dated-reform defects the contract was written to catch.
-- `full_allpass_uk_2.126.8.json`: the full run the gate expects. Every route and case, seed 0, `max_examples=20`, and population checks on the certified `enhanced_frs_2024_25` (SHA-256 `5ba399ea…`). The model was policyengine-uk 2.126.8 from the policyengine-uk#2305 branch with core 3.33.0, a development combination rather than a certified pair, so treat its `versions` as fixture metadata. Result: 267 pass, 6 pending decision d1344, 67 unsupported with reasons, both properties passing, 13 of 13 population checks; 20.6 minutes, peak RSS 2.7 GB.
 - `full_released_uk_2.130.1.json`: the full run of contract 1.1.0 (16 October 2026), the runner at policyengine.py#574's head merged with main 8a303636, on the certified pair policyengine-uk 2.130.1 with core 3.33.0: every route and case, seed 0, `max_examples=20`, population checks on the certified `enhanced_frs_2024_25` (uk-data 1.58.1, SHA-256 `056e80fd…`). Result: 792 pass, 25 pending a methodology call (d1344 and policyengine-uk#2396), 101 unsupported with reasons, both properties passing, 19 of 19 population rows; 29.6 minutes, peak RSS 3.5 GB. Its `versions` record policyengine 6.4.0, the stale metadata of the editable install that ran it; treat them as fixture metadata. The gate tests read it through the coverage the current runner module declares, and fail rather than skip when the runner's contract version moves past it. It replaces the 1.0.0 run on policyengine-uk 2.126.12.
-- `population_pass_max_examples_0.json`: population checks only, on the same dataset. It has no cases, and with `max_examples=0` its sampled properties did not run, so the gate treats it as an incomplete run.
+- `population_pass_max_examples_0.json`: population checks only, on the earlier certified `enhanced_frs_2024_25` (uk-data 1.58.0, SHA-256 `5ba399ea…`). It has no cases, and with `max_examples=0` its sampled properties did not run, so the gate treats it as an incomplete run.
 
-The only edits: `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
+The edits:
+- `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
+- Population rows are computed on the survey dataset, so a count from 1 to 9 in their `detail` is a small cell, which the metrics tool's `privacy.py` rule never publishes. In `full_released_uk_2.130.1.json`, `2027_people_with_lower_tax` and `payments_lower` (three rows each) are replaced by `"fewer than 10"`, as `publishable_contract_report` writes them to the qualification ledger. No gate rule reads `detail`. Check any new fixture for such counts before committing it.
+
+The run of contract 1.0.0 on policyengine-uk 2.126.8 (`full_allpass_uk_2.126.8.json`) was removed once no test read it.
diff --git a/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json b/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json
deleted file mode 100644
index 4c3feeb6..00000000
--- a/tests/fixtures/uk_contract/full_allpass_uk_2.126.8.json
+++ /dev/null
@@ -1,3665 +0,0 @@
-{
- "cases": [
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "1cf30cfa43f9bcee4bbb7c3d7d42d481aafe57cb674b93709b952a6089e23665",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "c24ddebf09ef159ad38ebd530d2deca18d2ec7165400a6d92ada5c9d6175377e",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "unchanged before 2027-28",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "held from 6 April 2027",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2026",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "april_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "eab1e87614e840127bd7b77723df34e4412b2cc05d1dee4326e255c08aae4087",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "f504a06f3382203f96a08fc1c07b86a0f001d4b40c0a2e805f6c0c4d29c50221",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "april_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "cd54b3b3b30cfd71448cbeb374c5d31aedca3d52733ab5c81e542feaba80704c",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_rate_change",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5a0ca24b82794f7c32123733efa38f90aa602676efa5219e4a13d97ff46f69ea",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "5e2b0da064082c7c363dec99c7e5bab2f190ae2f5ff9633454f1e10223293323",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "in force on 30 April 2027",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "prior law after 5 April 2028",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2027",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3486.0,
-   "case_id": "finite_rate_change",
-   "check": "baseline_isolation:income_tax:2028",
-   "expected": 3486.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ed4782036ee619f8c07483cac573d44bf1917fa33d3fa49a8551eebb632852ef",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "97674d142cf5719ae87a2523e758805be566fe02241aeff2a658fee27235c3f8",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 174.300048828125,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2027",
-   "decision_id": null,
-   "expected": 174.29999999999967,
-   "holds": null,
-   "oracle": "(30,000 - personal allowance) x (new rate - current rate); the allowance and current rate are read from current law",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "finite_rate_change",
-   "check": "change:income_tax:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "the change has ended",
-   "reform_digest": "635e34257a38637cabd07234afb9e37355921ce7b680a98d8f85a1e05ecbbb64",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "finite_rate_change",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "234ec5c3931182f8f76930655330ebbdb77a6e62586a0af81f386149be5c5036",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "725339aa214a4609707b6c10f7e32fdfb2491ad2e48da70f39a414dfc1f83aca",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 37700.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "decision_id": null,
-   "expected": 37700.0,
-   "holds": null,
-   "oracle": "frozen",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 12570.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "decision_id": null,
-   "expected": 12570.0,
-   "holds": null,
-   "oracle": "aligned with the allowance",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 50270.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "decision_id": null,
-   "expected": 50270.0,
-   "holds": null,
-   "oracle": "allowance + basic rate limit",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 241.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "decision_id": null,
-   "expected": 241.73,
-   "holds": null,
-   "oracle": "12,570 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 966.73,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "decision_id": null,
-   "expected": 966.73,
-   "holds": null,
-   "oracle": "50,270 / 52, to the penny",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": null,
-   "expected": 13630.0,
-   "holds": null,
-   "oracle": "contract 1.0.0: prior law's projected path resumes",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13630.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "decision_id": "d1344",
-   "expected": 12830.0,
-   "holds": false,
-   "oracle": "ITA 2007 s57 from the frozen \u00a312,570 with 2034's September CPI rise",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 41000.0,
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "decision_id": "d1344",
-   "expected": 38500.0,
-   "holds": false,
-   "oracle": "ITA 2007 s21 from the frozen \u00a337,700 with 2034's September CPI rise",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pending"
-  },
-  {
-   "actual": 3424.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2031",
-   "expected": 3424.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3372.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2032",
-   "expected": 3372.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 3318.39990234375,
-   "case_id": "extended_freeze",
-   "check": "baseline_isolation:income_tax:2033",
-   "expected": 3318.39990234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "423fc235458423a35a13511dffa5b18190c7e1d0e7b3a209d4b923708dd647f0",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "b53bec711f02356d55dbb011544c0e556eba7559496d89d10ae266da9e217a0e",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2031",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 52.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2031",
-   "decision_id": null,
-   "expected": 52.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2032",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 104.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2032",
-   "decision_id": null,
-   "expected": 104.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.lower_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_4.thresholds.upper_profits_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.upper_earnings_limit:2033",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "actual": 158.0,
-   "case_id": "extended_freeze",
-   "check": "change:income_tax:2033",
-   "decision_id": null,
-   "expected": 158.0,
-   "holds": null,
-   "oracle": "basic rate x (current law's allowance - 12,570)",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2034",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f0cebbfddd5f9a74d7ebb7f83247004201148486b8714cd916087872ce2dfaaa",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "extended_freeze",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "e98d41db2ed7d855dda05d65e66e1e4ef4b4167088a2d88bbd92c9b3260402ff",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "0ab5df46a43311bce2af6c4b9b70155c64df30388c8a0f99f15a2846351f715a",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5426.7763671875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2029",
-   "expected": 5426.7763671875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5098.7998046875,
-   "case_id": "april_benefit_uprating",
-   "check": "baseline_isolation:uc_standard_allowance:2026",
-   "expected": 5098.7998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "33b86ab43be584c8c6e8aafdd55053dcf72078a3a525cd638f38bcd1d645227f",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "dfc339899202506f1bb7300cea49e605d3c128f1c036c0ec5df0c3d326d0c33e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "april_benefit_uprating",
-   "check": "variable:uc_standard_allowance:2029",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "held from April 2028",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "april_benefit_uprating",
-   "check": "change:uc_standard_allowance:2026",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "d4388eb374c51a6da454f1325fe7699aca1a9004b95dae95464c3a9b2aea8bd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "april_benefit_uprating",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d646393894abdc73e4d317eff0c39419cfbf5f69df4dfea57f44db7700f1fd54",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "ba3722100cf3de0524dfd14b8e0b498a4c2caebe66bdf38395ae8d4568589236",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5216.06103515625,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2027",
-   "expected": 5216.06103515625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5320.3740234375,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2028",
-   "expected": 5320.3740234375,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5535.2998046875,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "baseline_isolation:uc_standard_allowance:2030",
-   "expected": 5535.2998046875,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "20b97441158d9b07c0a62a5bfd332aaa4ab9749ac9a9d3b93f046461f54acfc4",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "6df62a9f41db002ef95cadf25f2cd566de071a424141ebd1c479e4398ead4a4e",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": "change:uc_standard_allowance:2030",
-   "decision_id": null,
-   "expected": 0.0,
-   "holds": null,
-   "oracle": "prior law's uprated path resumes",
-   "reform_digest": "48f71ddba48e9494e868325cf1af191218d7edb5c4846616dbe75500e6db417d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "bounded_change_on_uprated_benefit",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "3d8fd4c48241e68e1e1d8479b2b2067b274092a7c4fc2476b7cea829c18aa588",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "576ce816dacf70876bdfd765e57f48d44a9499181cca2b3e178dfaf51cbad0bd",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18868852459016394,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "decision_id": null,
-   "expected": 0.18868852459016502,
-   "holds": null,
-   "oracle": "day-weighted: 207 days at 18% and 159 at 20% of 366",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "in force all year",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.18000000000000002,
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "decision_id": null,
-   "expected": 0.18,
-   "holds": null,
-   "oracle": "before the change",
-   "reform_digest": "abe5e3d10b5669e954ed794facadad012121eef44cc1444801edb99a6c902081",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "f9f1430783586c75c5ce96f54a3e4ee30af28059391bcfb9d0cb16d4230184e5",
-   "route": "wrapper.household",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2027",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2028",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": "parameter:gov.hmrc.cgt.basic_rate:2026",
-   "reason": "this route exposes outputs, not parameter values",
-   "reform_digest": "772a73501537a9c16f95dadad9ad48d044520ef6f92b0f53345c881b8250b5b7",
-   "route": "wrapper.policy",
-   "status": "unsupported"
-  },
-  {
-   "case_id": "mid_year_blended_rate",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "8bd9476925c59e9d13946308e4604e33976dc8a1d68b63e276628c95135a82d0",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "afe5d61179ae6fd02453405015018bcbdd8047fcc3e69e23c43e5f57dce17c67",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 13200.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.allowances.personal_allowance.amount:2031",
-   "decision_id": null,
-   "expected": 13200.0,
-   "holds": null,
-   "oracle": "ITA 2007 s57(3)",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 39600.0,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[1].threshold:2031",
-   "decision_id": null,
-   "expected": 39600.0,
-   "holds": null,
-   "oracle": "ITA 2007 s21(3)",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 253.85,
-   "case_id": "september_cpi_moves_indexed_thresholds",
-   "check": "parameter:gov.hmrc.national_insurance.class_1.thresholds.primary_threshold:2031",
-   "decision_id": null,
-   "expected": 253.85,
-   "holds": null,
-   "oracle": "aligned with the allowance, weekly",
-   "reform_digest": "fda4228463d1ee4cd7263094d2b28ffb49c78d09b87468542dba7e6821ff3f9d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "12bcb296368c2b63f30b2040bfa5c84678f0bd52aaf7f85d510a75cd70f995c3",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "909e6875b8d449e87b5d3eb0ad74e584e80241b9f40677343430b41232b20c5f",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5259.26806640625,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "baseline_isolation:uc_LCWRA_element:2027",
-   "expected": 5259.26806640625,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "9947c105e6b609c8a5f2c13ce4707daad40cfa8529bf2487734ef2a513169e8d",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "a695bb7865a505dbbcb9c973b674a5666804e15838252c66bb7e84fa082388f0",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": "variable:uc_LCWRA_element:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "88900943775d8451bee562422107eca7016ee21042a516b295fe3c00bc9a7da9",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "uc_rebalancing_reform_after_data_load",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "d837da2e6fabde655a05b130322e0c29d06d5d493ad99183a699198dc5e1d4b2",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "f0cad18ed901a4062c12dd721fa663915f3329fad55f54bbe407922de196d60d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.0,
-   "case_id": "structural_switch",
-   "check": "baseline_isolation:marriage_allowance:2026",
-   "expected": 0.0,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "19b28590adbd8d9b80069a5504380f0226f0a1e5b1b2f73f5ba411fc562d7742",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "f76cc80028ce85017f3730a4d7db21c8a69f7b68bae0123c0aed45df087b1393",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 1260.0,
-   "case_id": "structural_switch",
-   "check": "variable:marriage_allowance:2026",
-   "decision_id": null,
-   "expected": 1260.0,
-   "holds": null,
-   "oracle": "10% of the \u00a312,570 allowance, rounded up to \u00a310 (ITA 2007 s55B)",
-   "reform_digest": "6e7e98694b32def0a541b52e0abb79b1cdcfc1e50a70784147d24a17e652ffe0",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "structural_switch",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "062a65e94c93f043b9ff9322b07152c930d1e1cb375237eb2375343a9e470e73",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8a1e1a66ee167c2dc554452d46828576b58159ed3d3276ffa1723f417d5ade0d",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:baseline_vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_isolation:vat:2026",
-   "expected": 5263.158203125,
-   "oracle": "the reformed simulation's baseline equals an unreformed simulation",
-   "reform_digest": "8df662d00e257aeda318ef34432e8de4ab0474fcd093ab9afd16e5fd97c4f096",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 5263.158203125,
-   "case_id": "baseline_vat_is_current_law",
-   "check": "baseline_equals:baseline_vat:2026",
-   "decision_id": null,
-   "expected": 5263.158203125,
-   "holds": null,
-   "oracle": "baseline_vat is the unreformed vat",
-   "reform_digest": "ee8e8cffbe252201a18cc7581c191e14f1b0269bfcfaf9d48cde191e9b2aaae9",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "8465ddfc32335f10bb9d23b050f0156a37c48e8a10dc35719d6b7e4f6d1a9238",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "a72b9604c243f77845e1446379e85bd2eca8e0fa7c671956a26e05ecadc3c4a7",
-   "route": "country.scenario_parameter_changes",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Could not find the parameter gov.budget_2026.new_credit.amount (failed at budget_2026).",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "32c326f8ca94bac9e220000e7f0fcf1a34bccd4947357e3819d419bb6ff193ea",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "292d055c4ba7f1a326b9fa798441a0f6d2186c07206ce7d63177d829371ee335",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": "ValueError: Reform contains parameter paths not defined on policyengine-uk 2.125.1:\n  - 'gov.budget_2026.new_credit.amount'",
-   "case_id": "unknown_path",
-   "check": "rejected",
-   "expected": "an error matching 'new_credit'",
-   "reform_digest": "29a0b52eda9615814b814d0de2932d01d8d59430150dcbf9fbb2fcdf79d1fd8d",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "case_id": "unknown_path",
-   "check": null,
-   "reason": "Runs in policyengine-sim-api's deploy gate, which imports CASES and routes them through its runtime; it is not callable in-process.",
-   "reform_digest": null,
-   "route": "api.sim_api",
-   "status": "unsupported"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "fiscal year 2027",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "that year only",
-   "reform_digest": "3314f6d0362de9643ce2022904e4fcbbe84297c25d36c37add61a878c7dc3e9c",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2026",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "before 1 January 2027",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "from 1 January 2027",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.21,
-   "case_id": "reading_bare_year_reform_from_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.21,
-   "holds": null,
-   "oracle": "onwards",
-   "reform_digest": "d19ea548203c2417e712543d47546f3fa48c741252ccd5b6bf1664d9a517d6b6",
-   "route": "country.reform_from_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2027",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "one day is not 30 April",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 0.2,
-   "case_id": "reading_single_day_dict",
-   "check": "parameter:gov.hmrc.income_tax.rates.uk[0].rate:2028",
-   "decision_id": null,
-   "expected": 0.2,
-   "holds": null,
-   "oracle": "one day only",
-   "reform_digest": "dec76eb1ea64e800caff37168afaaa26599bb03b533c169908d691c111cdbc36",
-   "route": "country.reform_dict",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "56c7ad7d1ddf6185703a5f60d31f11a12272e1166c667996b484801f57dbebcd",
-   "route": "wrapper.household",
-   "status": "pass"
-  },
-  {
-   "actual": 6000.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2027",
-   "decision_id": null,
-   "expected": 6000.0,
-   "holds": null,
-   "oracle": "\u00a3500 x 12",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  },
-  {
-   "actual": 6240.0,
-   "case_id": "reading_effective_dates_reverse_order",
-   "check": "variable:uc_standard_allowance:2028",
-   "decision_id": null,
-   "expected": 6240.0,
-   "holds": null,
-   "oracle": "\u00a3520 x 12",
-   "reform_digest": "b09577ce022e4cc30b4702add142a1e3aa1ab438a27955d182bba894199cecd5",
-   "route": "wrapper.policy",
-   "status": "pass"
-  }
- ],
- "contract_id": "policyengine-uk/budget-reform-contract",
- "contract_version": "1.0.0",
- "dataset": {
-  "path": "",
-  "sha256": "5ba399ea5ab9a6c7d4e9aaf6c623080beb34d9ad5f330f6244dbad72b8d960b6"
- },
- "elapsed_seconds": 1234.3,
- "holds": true,
- "max_examples": 20,
- "population": [
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_baseline_isolation",
-   "detail": null,
-   "route": "unreformed",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_query_order",
-   "detail": null,
-   "route": "unreformed",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_routes_agree",
-   "route": "country.reform_dict = country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_routes_agree",
-   "route": "country.reform_dict = country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0
-   },
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0
-   },
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_april_rate_change",
-   "detail": {
-    "2026_unchanged": true,
-    "2027_people_with_higher_tax": 1093,
-    "2027_people_with_lower_tax": 0
-   },
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.reform_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.scenario_parameter_changes",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  },
-  {
-   "check_id": "population_finite_change_expires",
-   "route": "country.reform_from_dict",
-   "seed": 0,
-   "status": "pass",
-   "subsample_households": 1000
-  }
- ],
- "prior_law_option": "projected",
- "properties": [
-  {
-   "engine": "hypothesis",
-   "examples_run": 20,
-   "property_id": "annual_values_match_the_oracle",
-   "status": "pass"
-  },
-  {
-   "engine": "hypothesis",
-   "examples_run": 20,
-   "property_id": "routes_agree_and_baselines_hold",
-   "status": "pass"
-  }
- ],
- "routes": [
-  "country.reform_dict",
-  "country.scenario_parameter_changes",
-  "country.reform_from_dict",
-  "wrapper.household",
-  "wrapper.policy",
-  "api.sim_api"
- ],
- "seed": 0,
- "summary": {
-  "error": 0,
-  "fail": 0,
-  "pass": 267,
-  "pending": 6,
-  "unsupported": 67
- },
- "versions": {
-  "policyengine": "6.2.6",
-  "policyengine-core": "3.33.0",
-  "policyengine-uk": "2.126.8"
- }
-}
diff --git a/tests/fixtures/uk_contract/full_released_uk_2.130.1.json b/tests/fixtures/uk_contract/full_released_uk_2.130.1.json
index b19bbd81..c2e15f68 100644
--- a/tests/fixtures/uk_contract/full_released_uk_2.130.1.json
+++ b/tests/fixtures/uk_contract/full_released_uk_2.130.1.json
@@ -14715,7 +14715,7 @@
       "detail": {
         "2026_unchanged": true,
         "2027_people_with_higher_tax": 1093,
-        "2027_people_with_lower_tax": 4,
+        "2027_people_with_lower_tax": "fewer than 10",
         "2027_total_change": 205573.0608100891
       },
       "reform_identity": null,
@@ -14730,7 +14730,7 @@
       "detail": {
         "2026_unchanged": true,
         "2027_people_with_higher_tax": 1093,
-        "2027_people_with_lower_tax": 4,
+        "2027_people_with_lower_tax": "fewer than 10",
         "2027_total_change": 205573.0608100891
       },
       "reform_identity": null,
@@ -14745,7 +14745,7 @@
       "detail": {
         "2026_unchanged": true,
         "2027_people_with_higher_tax": 1093,
-        "2027_people_with_lower_tax": 4,
+        "2027_people_with_lower_tax": "fewer than 10",
         "2027_total_change": 205573.0608100891
       },
       "reform_identity": null,
@@ -14788,7 +14788,7 @@
         "awards_lower": 0,
         "payments_below_the_payable_floor": 0,
         "payments_higher": 102,
-        "payments_lower": 1,
+        "payments_lower": "fewer than 10",
         "payments_not_award_less_deductions": 0,
         "standard_allowance_scaled_10_percent": true,
         "units_with_non_finite_values": 0
@@ -14806,7 +14806,7 @@
         "awards_lower": 0,
         "payments_below_the_payable_floor": 0,
         "payments_higher": 102,
-        "payments_lower": 1,
+        "payments_lower": "fewer than 10",
         "payments_not_award_less_deductions": 0,
         "standard_allowance_scaled_10_percent": true,
         "units_with_non_finite_values": 0
@@ -14824,7 +14824,7 @@
         "awards_lower": 0,
         "payments_below_the_payable_floor": 0,
         "payments_higher": 102,
-        "payments_lower": 1,
+        "payments_lower": "fewer than 10",
         "payments_not_award_less_deductions": 0,
         "standard_allowance_scaled_10_percent": true,
         "units_with_non_finite_values": 0
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index b3448ceb..4b21e697 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -825,6 +825,12 @@ def _run_contract(
 
 def _run_released_contract(report, *, pending_decisions=()):
     """Gate a fixture through the real runner's declarations and route logic."""
+
+    return _released_contract_outcome(report, pending_decisions=pending_decisions)[0]
+
+
+def _released_contract_outcome(report, *, pending_decisions=()):
+    """``(result, evidence)`` of ``_run_released_contract``."""
     import importlib
     import types
 
@@ -853,7 +859,7 @@ def importer(name):
         max_examples=20,
         dataset_path=Path("enhanced_frs_2024_25.h5"),
         pending_decisions=pending_decisions,
-    )[0]
+    )
 
 
 def test_the_released_models_full_run_passes_the_runners_own_declarations():
@@ -861,15 +867,111 @@ def test_the_released_models_full_run_passes_the_runners_own_declarations():
 
     result = _run_released_contract(_fixture("full_released_uk_2.130.1.json"))
     assert result.status == "pass", result.summary
-    assert result.details["counts"] == {
-        "pass": 792,
-        "fail": 0,
-        "error": 0,
-        "unsupported": 101,
-        "pending": 25,
+    assert result.details["counts"] == RELEASED_COUNTS
+
+
+RELEASED_COUNTS = {
+    "pass": 792,
+    "fail": 0,
+    "error": 0,
+    "unsupported": 101,
+    "pending": 25,
+}
+
+
+def test_the_released_run_without_assertion_ids_resolves_by_oracle_and_order():
+    """Round 10 of #574: every row of the 1.1.0 run has an assertion_id, so
+    the gate's resolution of rows without one (by oracle, then order) no
+    longer ran on real data, and three mutants of it survived."""
+
+    report = _fixture("full_released_uk_2.130.1.json")
+    for row in report["cases"]:
+        row.pop("assertion_id", None)
+    result = _run_released_contract(report)
+    assert result.status == "pass", result.summary
+    assert result.details["counts"] == RELEASED_COUNTS
+
+
+def test_the_ledger_never_publishes_a_small_count_from_the_dataset():
+    """Round 10 of #574: population rows are computed on the survey data, so
+    a count from 1 to 9 in their detail is suppressed in the evidence the
+    ledger publishes, and the published digest is of that evidence, never
+    of the full report (whose digest would give the count back)."""
+
+    from policyengine.provenance.uk_candidate import SUPPRESSED_COUNT
+
+    report = _fixture("full_released_uk_2.130.1.json")
+    for row in report["population"]:
+        if row["check_id"] == "population_uc_standard_allowance_plus_10":
+            row["detail"]["payments_lower"] = 3  # synthetic small count
+    result, evidence = _released_contract_outcome(report)
+    assert result.status == "pass", result.summary
+    published = [
+        row["detail"]
+        for row in evidence["population"]
+        if row["check_id"] == "population_uc_standard_allowance_plus_10"
+    ]
+    assert {detail["payments_lower"] for detail in published} == {SUPPRESSED_COUNT}
+    assert {detail["payments_higher"] for detail in published} == {102}
+    assert {detail["awards_lower"] for detail in published} == {0}
+    assert result.details["report_sha256"] == gates_module.evidence_sha256(evidence)
+    assert result.evidence_sha256 == gates_module.evidence_sha256(evidence)
+    # Everything but the population details is published as reported.
+    assert {k: v for k, v in evidence.items() if k != "population"} == {
+        k: v for k, v in report.items() if k != "population"
     }
 
 
+@settings(max_examples=200, deadline=None)
+@given(
+    detail=st.recursive(
+        st.one_of(
+            st.integers(-20, 2000),
+            st.booleans(),
+            st.floats(allow_nan=False, allow_infinity=False),
+            st.none(),
+            st.text(max_size=5),
+        ),
+        lambda children: (
+            st.lists(children, max_size=3)
+            | st.dictionaries(st.text(max_size=5), children, max_size=3)
+        ),
+        max_leaves=10,
+    )
+)
+def test_no_count_from_one_to_nine_survives_publication(detail):
+    from policyengine.provenance.uk_candidate import (
+        SUPPRESSED_COUNT,
+        publishable_contract_report,
+    )
+
+    report = {"cases": [{"detail": detail}], "population": [{"detail": detail}]}
+    published = publishable_contract_report(report)
+
+    def leaves(value):
+        if isinstance(value, dict):
+            for item in value.values():
+                yield from leaves(item)
+        elif isinstance(value, list):
+            for item in value:
+                yield from leaves(item)
+        else:
+            yield value
+
+    for leaf in leaves(published["population"][0]["detail"]):
+        assert isinstance(leaf, bool) or not (isinstance(leaf, int) and 0 < leaf < 10)
+    # Synthetic case rows and every other value are left alone.
+    assert published["cases"] == report["cases"]
+    before, after = (
+        list(leaves(detail)),
+        list(leaves(published["population"][0]["detail"])),
+    )
+    assert len(before) == len(after)
+    for old, new in zip(before, after):
+        small = not isinstance(old, bool) and isinstance(old, int) and 0 < old < 10
+        assert new == (SUPPRESSED_COUNT if small else old)
+
+
 @pytest.mark.parametrize("section", ["cases", "population"])
 def test_supported_failures_cannot_be_relabelled_unsupported(section):
     report = _fixture("full_released_uk_2.130.1.json")
@@ -1061,20 +1163,24 @@ def test_the_runners_own_run_level_row_is_recognised():
 
     from policyengine.tax_benefit_models.uk import budget_reform_contract as runner
 
-    def gated(check):
+    def gated(current):
+        # The runner's whole row, so a renamed case or route fails too
+        # (round 10 of #574).
         report = _passing_report()
-        row = next(
-            row
-            for row in report["cases"]
+        index = next(
+            index
+            for index, row in enumerate(report["cases"])
             if row["case_id"] == "module_parameters_unchanged"
         )
-        row["check"] = check
+        report["cases"][index] = current
         return _run_contract(report)
 
     current = runner.module_parameters_unchanged(runner.shared_state())
     assert current["status"] == "pass"
-    assert gated(current["check"]).status == "pass", gated(current["check"]).summary
-    unrelated = gated("every case's reform digest in policyengine-uk")
+    assert gated(current).status == "pass", gated(current).summary
+    unrelated = gated(
+        {**current, "check": "every case's reform digest in policyengine-uk"}
+    )
     assert unrelated.status == "error"
     assert any(
         "does not identify the shared parameter check" in problem

From 464bf31ce4dcb9379cabc002a46645e42db56144 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 02:32:09 -0400
Subject: [PATCH 40/45] Withhold every value from an unsafe metrics report;
 compare signed exclusions

supp-r2 findings on the metrics gate:

- P1: a report that breaks the small-cell format was withheld from the
  ledger, but its values still reached the comparison's moves and the
  responsiveness table, which the ledger also publishes. Now neither
  gate compares or records any value when a report breaks the format
  (the comparison's values_withheld), the responsiveness gate checks the
  format itself (an error), and the tool's detail text is dropped too.
  Duplicate metric rows are part of the format check, so the ledger
  never publishes a public copy beside a suppressed one.
- P1: equal excluded ids with different signs took the equal-exclusion
  fast path; the tool compares the signed maps. Exclusions are now equal
  only when their signs are, so such a total is withheld in every
  section.
- P2: a published head's caseload counts only its positive records, so
  it can be suppressed on its own; only a published caseload beside a
  suppressed head fails now.
- Test gaps: shared exclusions skipped when lining up (M03), negative
  heads (M06), a zero sign (M09), a boolean year (M15), and an
  unfinished report still checked before publication (M28); the
  lining-up property now generates opposite signs and asserts that a
  move is recorded exactly when expected.

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py |  92 +++++---
 tests/test_uk_candidate_gates.py            | 229 ++++++++++++++++----
 2 files changed, 247 insertions(+), 74 deletions(-)

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index b1b52c13..00d19985 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1418,25 +1418,36 @@ def _small_cell_problems(name: str, rows: Sequence[Mapping[str, Any]]) -> list[s
     """Rows that break the tool's small-cell format, as problems.
 
     The tool publishes a figure from fewer than 10 records with ``value``
-    null and ``suppressed`` true. A spending head's caseload is suppressed
-    with it, from the same records. Every total holding a suppressed figure
-    is rebuilt without it; the total lists the figure's ``metric_id`` under
-    ``excludes`` and the sign it enters with, +1 or -1, under
-    ``exclude_signs`` (``privacy.py``, ``measure.measure_year`` and
+    null and ``suppressed`` true. A suppressed spending head's caseload is
+    suppressed with it; a published head's caseload counts only positive
+    records, so it can be suppressed on its own. Every total holding a
+    suppressed figure is rebuilt without it; the total lists the figure's
+    ``metric_id`` under ``excludes`` and the sign it enters with, +1 or -1,
+    under ``exclude_signs`` (``privacy.py``, ``measure.measure_year`` and
     ``measure.rebuild_protected`` in the pinned tool). These are reports this
-    gate cannot read safely:
+    gate cannot read safely, so neither the gate's evidence nor the ledger
+    records any value from them:
 
     - a row without the small-cell fields, or whose year is not an integer;
+    - two rows for one figure and year (one could publish what the other
+      suppresses);
     - a suppressed row with a value, or a ``suppressed`` that is not a
       boolean;
     - an ``excludes`` that is not a list of ids, or names a figure the same
       report does not suppress in that year;
     - ``exclude_signs`` that do not give +1 or -1 for exactly ``excludes``;
-    - a caseload and its spending head that are not suppressed together.
+    - a published caseload beside its suppressed spending head.
     """
 
     by_key = {(str(row.get("metric_id")), row.get("year")): row for row in rows}
     hidden = {key for key, row in by_key.items() if _suppressed(row)}
+    repeated = sorted(
+        f"{key[0]} {key[1]}"
+        for key, count in Counter(
+            (str(row.get("metric_id")), row.get("year")) for row in rows
+        ).items()
+        if count > 1
+    )
     missing_fields, bad_years, with_value, not_boolean = [], [], [], []
     malformed, bad_signs, unmatched, unpaired = [], [], [], []
     for row in rows:
@@ -1451,9 +1462,9 @@ def _small_cell_problems(name: str, rows: Sequence[Mapping[str, Any]]) -> list[s
             not_boolean.append(label)
         elif flag and row.get("value") is not None:
             with_value.append(label)
-        if metric_id.startswith("caseloads."):
+        if metric_id.startswith("caseloads.") and not _suppressed(row):
             head = by_key.get((f"spending.{metric_id.split('.', 1)[1]}", year))
-            if head is not None and _suppressed(head) != _suppressed(row):
+            if head is not None and _suppressed(head):
                 unpaired.append(label)
         excludes = row.get("excludes", [])
         if not isinstance(excludes, list) or not all(
@@ -1476,12 +1487,13 @@ def _small_cell_problems(name: str, rows: Sequence[Mapping[str, Any]]) -> list[s
             "exclude_signs), so from a tool that predates suppression",
         ),
         (bad_years, "metric rows whose year is not an integer"),
+        (repeated, "duplicate metrics"),
         (with_value, "suppressed figures with a value"),
         (not_boolean, "a suppressed flag that is not true or false"),
         (malformed, "excludes that are not a list of metric ids"),
         (bad_signs, "exclude_signs that are not +1 or -1 for exactly its excludes"),
         (unmatched, "totals excluding a figure it does not suppress"),
-        (unpaired, "caseloads not suppressed together with their spending head"),
+        (unpaired, "caseloads published beside their suppressed spending head"),
     ):
         if found:
             problems.append(f"the {name} report has {what}: {', '.join(found[:8])}")
@@ -1714,16 +1726,8 @@ def compare_metric_reports(
         ("candidate", candidate.get("metrics", [])),
         ("previous", previous.get("metrics", [])),
     )
+    unsafe = False
     for name, rows in report_metric_rows:
-        metric_counts = Counter(_metric_key(row) for row in rows)
-        duplicate_metrics = sorted(
-            f"{key[0]} {key[1]}" for key, count in metric_counts.items() if count > 1
-        )
-        if duplicate_metrics:
-            problems.append(
-                f"the {name} report has duplicate metrics: "
-                + ", ".join(duplicate_metrics[:8])
-            )
         # A suppressed figure is published without a value by design.
         nonfinite = [
             f"{row.get('metric_id')} {row.get('year')}"
@@ -1734,7 +1738,9 @@ def compare_metric_reports(
             problems.append(
                 f"the {name} report has non-finite values: {', '.join(nonfinite[:8])}"
             )
-        problems.extend(_small_cell_problems(name, rows))
+        format_problems = _small_cell_problems(name, rows)
+        problems.extend(format_problems)
+        unsafe = unsafe or bool(format_problems)
     lost = sorted(f"{key[0]} {key[1]}" for key in set(before_metrics) - set(current))
     if lost:
         problems.append(f"metrics disappeared: {', '.join(lost[:8])}")
@@ -1747,9 +1753,13 @@ def compare_metric_reports(
     withheld: list[dict[str, Any]] = []
     aligned_totals: list[str] = []
     suppressed_on_both = 0
+    # A report that breaks the small-cell format may carry a figure from
+    # fewer than 10 records: it fails above, and no value from either report
+    # enters the evidence, which the public ledger publishes.
+    comparable = {} if unsafe else current
     # Years sort as text so a malformed year (failed above) cannot crash this.
     for key, row in sorted(
-        current.items(), key=lambda item: (item[0][0], str(item[0][1]))
+        comparable.items(), key=lambda item: (item[0][0], str(item[0][1]))
     ):
         old = before_metrics.get(key)
         if old is None:
@@ -1774,20 +1784,17 @@ def compare_metric_reports(
         new_value, old_value = float(row["value"]), float(old["value"])
         new_compared, old_compared = new_value, old_value
         aligned_on: Optional[list[str]] = None
-        if _excludes(row) != _excludes(old):
-            # Each side leaves out its own suppressed figures. Subtracting
-            # the totals as published would mix definitions and could give
-            # an excluded figure back, so they are lined up first, from
-            # published figures only, or withheld.
-            new_signs, old_signs = _valid_signs(row), _valid_signs(old)
+        # Both reports passed the format check, so their signs are valid.
+        new_signs, old_signs = _valid_signs(row) or {}, _valid_signs(old) or {}
+        if new_signs != old_signs:
+            # Each side leaves out its own suppressed figures, each with its
+            # sign (the tool compares the signed maps, whose keys are the
+            # excluded ids). Subtracting the totals as published would mix
+            # definitions and could give an excluded figure back, so they are
+            # lined up first, from published figures only, or withheld.
             reason = None
             if not (_additive(row) and _additive(old)):
                 reason = "the reports leave out different suppressed figures"
-            elif new_signs is None or old_signs is None:
-                reason = (
-                    "the reports leave out different suppressed figures, "
-                    "without the signs needed to line them up"
-                )
             elif any(
                 new_signs[metric_id] != old_signs[metric_id]
                 for metric_id in set(new_signs) & set(old_signs)
@@ -1868,6 +1875,9 @@ def compare_metric_reports(
         "suppressed_on_both_sides": suppressed_on_both,
         "withheld_changes": withheld,
         "lined_up_totals": aligned_totals,
+        # True when a report breaks the small-cell format: no value from
+        # either report was compared or recorded.
+        "values_withheld": unsafe,
         "moves_beyond_bounds": moves,
         "candidate_report_sha256": evidence_sha256(candidate),
         "previous_report_sha256": evidence_sha256(previous),
@@ -2045,6 +2055,10 @@ def reform_responsiveness(
     )
     if repeated:
         disagreements.append(f"the report repeats {', '.join(repeated[:8])}")
+    # A report that breaks the small-cell format may carry a figure from
+    # fewer than 10 records: no value from it enters the evidence.
+    format_problems = _small_cell_problems("candidate", report.get("metrics") or [])
+    disagreements.extend(format_problems)
     malformed: list[str] = []
     for reform in standard_reforms:
         reform_id = reform["id"]
@@ -2066,7 +2080,7 @@ def reform_responsiveness(
                     malformed.append(f"reform_targets.{reform_id} {year}")
                     recomputed = False
                 continue
-            changes[str(year)] = value
+            changes[str(year)] = None if format_problems else value
             if (
                 isinstance(value, bool)
                 or not isinstance(value, (int, float))
@@ -2084,7 +2098,8 @@ def reform_responsiveness(
             "withheld_years": withheld_years,
             "reform_runs": ran,
             "responsive": responsive.get("status"),
-            "detail": responsive.get("detail"),
+            # The tool's text can quote amounts; none from an unsafe report.
+            "detail": None if format_problems else responsive.get("detail"),
         }
         table.append(row)
         label = f"{reform['name']} ({reform_id})"
@@ -2093,7 +2108,14 @@ def reform_responsiveness(
         elif responsive.get("status") != "pass":
             problems.append(
                 f"{label} did not respond: "
-                + (responsive.get("detail") or "no responsive check in the report")
+                + (
+                    row["detail"]
+                    or (
+                        "its detail is withheld"
+                        if format_problems and responsive
+                        else "no responsive check in the report"
+                    )
+                )
             )
         if ran == "pass" and responsive.get("status") in ("pass", "fail"):
             passed = responsive["status"] == "pass"
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 4b21e697..10f78680 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -2003,11 +2003,8 @@ def test_totals_that_cannot_be_lined_up_are_withheld():
     candidate["metrics"][1]["exclude_signs"] = {}
     status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
     assert status == "fail" and "exclude_signs that are not +1 or -1" in summary
-    assert evidence["withheld_changes"][-1]["reason"] == (
-        "the reports leave out different suppressed figures, without the "
-        "signs needed to line them up"
-    )
-    assert evidence["moves_beyond_bounds"] == []
+    assert evidence["values_withheld"] is True
+    assert evidence["withheld_changes"] == evidence["moves_beyond_bounds"] == []
 
 
 def test_totals_at_equal_exclusions_compare_numerically():
@@ -2022,6 +2019,143 @@ def test_totals_at_equal_exclusions_compare_numerically():
     assert evidence["withheld_changes"] == []
 
 
+@pytest.mark.parametrize(
+    "kind", ["decile", "household_total", "model_total", "balance"]
+)
+def test_the_same_figure_excluded_with_opposite_signs_is_withheld(kind):
+    """supp-r2 P1: equal excluded ids are not equal exclusions when a sign
+    differs (the tool compares the signed maps), so the change is withheld,
+    never computed, in every section and both review steps."""
+
+    def side(sign, value):
+        return _cells(
+            [
+                (DSA, 2027, "spending", None, True, ()),
+                ("total", 2027, kind, value, False, (DSA,), {DSA: sign}),
+            ]
+        )
+
+    candidate, previous = side(1, 9.0e11), side(-1, 5.0e11)
+    status, _, evidence = compare_metric_reports(candidate, previous, BOUNDS)
+    assert status == "needs_review"
+    assert evidence["moves_beyond_bounds"] == evidence["lined_up_totals"] == []
+    (row,) = evidence["withheld_changes"]
+    assert row["metric_id"] == "total"
+    result, steps = metrics_review(
+        candidate_report=candidate,
+        previous_report=previous,
+        bounds=BOUNDS,
+        cross_report=candidate,
+    )
+    assert steps["model_only"]["moves_beyond_bounds"] == []
+    assert steps["model_only"]["withheld_changes"][0]["metric_id"] == "total"
+
+
+def test_figures_both_sides_exclude_are_skipped_when_lining_up():
+    """supp-r2 M03: the candidate excludes A and B, the previous report A
+    only; B (published there) is taken out of the previous total, A of
+    neither (it is suppressed on both sides). Values synthetic."""
+
+    other = "spending.other_head"
+    candidate = _cells(
+        [
+            (DSA, 2027, "spending", None, True, ()),
+            (other, 2027, "spending", None, True, ()),
+            (
+                "total",
+                2027,
+                "model_total",
+                4.0e11,
+                False,
+                (DSA, other),
+                {DSA: 1, other: -1},
+            ),
+        ]
+    )
+    previous = _cells(
+        [
+            (DSA, 2027, "spending", None, True, ()),
+            (other, 2027, "spending", 3.0e10, False, ()),
+            ("total", 2027, "model_total", 4.0e11 - 3.0e10, False, (DSA,), {DSA: 1}),
+        ]
+    )
+    evidence = compare_metric_reports(candidate, previous, BOUNDS)[2]
+    assert evidence["lined_up_totals"] == ["total 2027"]
+    assert evidence["moves_beyond_bounds"] == []
+
+
+def test_a_caseload_can_be_suppressed_beside_its_published_head():
+    """supp-r2 P2: a published head's caseload counts only its positive
+    records, so a head with negative values can be published while its
+    caseload is suppressed. Valid, and published to the ledger."""
+
+    from policyengine.provenance.uk_candidate import publishable_metrics_report
+
+    report = _small_cell_pair(head=(2.0e6, False, ()), total=(5.4e11, False, ()))
+    report["metrics"].append(
+        {
+            "metric_id": "caseloads.disabled_students_allowance",
+            "year": 2027,
+            "kind": "caseload",
+            "value": None,
+            "suppressed": True,
+            "excludes": [],
+            "exclude_signs": {},
+        }
+    )
+    status, summary, _ = compare_metric_reports(report, report, BOUNDS)
+    assert status == "pass", summary
+    assert publishable_metrics_report(report) == report
+
+
+def test_no_value_from_an_unsafe_report_enters_the_evidence():
+    """supp-r2 P1: a report that breaks the small-cell format fails, and
+    neither the comparison's moves nor the responsiveness table carries any
+    of its values (the ledger publishes both). Values synthetic."""
+
+    marker = 123456789.25
+    legacy = _report({("income_tax", 2027, "receipt"): marker})
+    for row in legacy["metrics"]:
+        for field in ("suppressed", "excludes", "exclude_signs"):
+            row.pop(field)
+    status, _, evidence = compare_metric_reports(
+        legacy, _report({("income_tax", 2027, "receipt"): 3.0e11}), BOUNDS
+    )
+    assert status == "fail" and evidence["values_withheld"] is True
+    assert str(marker) not in json.dumps(evidence)
+    result, steps = metrics_review(
+        candidate_report=legacy,
+        previous_report=_report({("income_tax", 2027, "receipt"): 3.0e11}),
+        bounds=BOUNDS,
+        cross_report=legacy,
+    )
+    assert str(marker) not in json.dumps(steps)
+
+    report = _responsive_report()
+    for row in report["metrics"]:
+        row.pop("exclude_signs")
+    result, evidence = reform_responsiveness_gate(report)
+    assert result.status == "error"
+    assert "rows without the small-cell fields" in result.summary
+    for reform in evidence["reforms"]:
+        assert set(reform["target_changes"].values()) == {None}
+        assert reform["detail"] is None
+
+
+def test_a_report_the_tool_could_not_finish_is_still_checked_before_publication():
+    """supp-r2 M28: an unfinished report with metrics in it is held to the
+    same format before the ledger publishes it."""
+
+    from policyengine.provenance.uk_candidate import publishable_metrics_report
+
+    report = _small_cell_pair()
+    report["status"] = "error"
+    report["metrics"][1]["value"] = 2.0e6
+    assert "withheld" in publishable_metrics_report(report)
+    unfinished = {"status": "error", "error": "Traceback ..."}
+    assert publishable_metrics_report(unfinished) == unfinished
+
+
 @pytest.mark.parametrize(
     ("mutate", "message"),
     [
@@ -2090,26 +2224,20 @@ def test_totals_at_equal_exclusions_compare_numerically():
                     **PUBLISHED,
                 }
             ),
-            "caseloads not suppressed together with their spending head: "
+            "caseloads published beside their suppressed spending head: "
             "caseloads.disabled_students_allowance 2027",
         ),
         (
-            lambda rows: (
-                rows[1].update(value=2.0e6, suppressed=False),
-                rows[2].update(excludes=[], exclude_signs={}),
-                rows.append(
-                    {
-                        "metric_id": "caseloads.disabled_students_allowance",
-                        "year": 2027,
-                        "kind": "caseload",
-                        "value": None,
-                        "suppressed": True,
-                        "excludes": [],
-                        "exclude_signs": {},
-                    }
-                ),
-            ),
-            "caseloads not suppressed together with their spending head",
+            lambda rows: rows[1].update(year=True),
+            "metric rows whose year is not an integer",
+        ),
+        (
+            lambda rows: rows[2].update(exclude_signs={DSA: 0}),
+            "exclude_signs that are not +1 or -1",
+        ),
+        (
+            lambda rows: rows.append(dict(rows[0])),
+            "duplicate metrics: income_tax 2027",
         ),
     ],
     ids=[
@@ -2127,7 +2255,9 @@ def test_totals_at_equal_exclusions_compare_numerically():
         "signs for a figure not excluded",
         "signs not a map",
         "zero caseload published beside a suppressed head",
-        "caseload suppressed beside a published head",
+        "year True",
+        "sign of 0",
+        "a figure twice",
     ],
 )
 @pytest.mark.parametrize("side", ["candidate", "previous"])
@@ -2263,24 +2393,32 @@ def side(choices):
 
 _SIDE = st.tuples(
     st.sampled_from(["published", "suppressed"]),
-    st.floats(min_value=1.0e8, max_value=5.0e10),
+    # Heads can be negative (supp-r2 M06): their published value is taken
+    # out with the sign, whatever its own sign.
+    st.one_of(
+        st.floats(min_value=1.0e8, max_value=5.0e10),
+        st.floats(min_value=-5.0e10, max_value=-1.0e8),
+    ),
     st.floats(min_value=-0.5, max_value=0.5, allow_nan=False),
+    # Each side's sign for the head; they differ only if the partition
+    # changed (supp-r2: opposite signs for one figure were never generated).
+    st.sampled_from([1, -1]),
 )
 
 
-@settings(max_examples=400, deadline=None)
+@settings(max_examples=500, deadline=None)
 @given(
     candidate_side=_SIDE,
     previous_side=_SIDE,
-    sign=st.sampled_from([1, -1]),
     kind=st.sampled_from(["model_total", "balance", "decile"]),
 )
-def test_lining_up_against_a_reference(candidate_side, previous_side, sign, kind):
+def test_lining_up_against_a_reference(candidate_side, previous_side, kind):
     """Differential against the tool's rule, stated independently: a head
-    published or suppressed on each side, a total that holds it with
-    ``sign`` where it is published and excludes it where it is not."""
+    published or suppressed on each side, a total that holds it with that
+    side's sign where it is published and excludes it, with that sign, where
+    it is not."""
 
-    def side(state, head, change):
+    def side(state, head, change, sign):
         rest = 4.0e11 * (1 + change)
         if state == "suppressed":
             rows = [
@@ -2296,7 +2434,10 @@ def side(state, head, change):
 
     candidate, c_rows = side(*candidate_side)
     previous, p_rows = side(*previous_side)
-    (c_state, c_head, _), (p_state, p_head, _) = candidate_side, previous_side
+    (c_state, c_head, _, c_sign), (p_state, p_head, _, p_sign) = (
+        candidate_side,
+        previous_side,
+    )
     c_total, p_total = c_rows[1][3], p_rows[1][3]
     review, lined_up, change = False, False, None
     if c_state == p_state == "published":
@@ -2304,26 +2445,30 @@ def side(state, head, change):
         review |= abs(c_head - p_head) > head_threshold
         change = c_total - p_total
     elif c_state == p_state == "suppressed":
-        change = c_total - p_total
+        if c_sign == p_sign:
+            change = c_total - p_total
+        else:
+            review = True  # one figure, two signs: withheld in every section
     else:
         review = True  # the head is withheld
         if kind in ("model_total", "balance"):
             lined_up = True
             # The side that publishes the head takes it out with the sign
-            # the other side records, exactly as the gate computes it.
+            # the excluding side records, exactly as the gate computes it.
             if c_state == "published":
-                change = (c_total - sign * c_head) - p_total
+                change = (c_total - p_sign * c_head) - p_total
             else:
-                change = c_total - (p_total - sign * p_head)
-    if change is not None and abs(change) > max(0.02 * abs(p_total), 5e8):
-        review = True
+                change = c_total - (p_total - c_sign * p_head)
+    moved = change is not None and abs(change) > max(0.02 * abs(p_total), 5e8)
+    review |= moved
     status, summary, evidence = compare_metric_reports(candidate, previous, BOUNDS)
     assert status == ("needs_review" if review else "pass"), summary
     assert evidence["lined_up_totals"] == (["total 2027"] if lined_up else [])
     total_moves = [
         m for m in evidence["moves_beyond_bounds"] if m["metric_id"] == "total"
     ]
-    if total_moves:
+    assert bool(total_moves) == moved
+    if moved:
         assert total_moves[0]["change"] == change
     for row in evidence["withheld_changes"]:
         assert set(row) <= {
@@ -2909,6 +3054,7 @@ def _responsive_report(scale=5.0, overrides=None, years=RESPONSE_YEARS, lie=None
                         "year": year,
                         "value": value,
                         "kind": "reform_target",
+                        **PUBLISHED,
                     }
                 )
         finite = {y: v for y, v in changes.items() if v == v}
@@ -3186,7 +3332,12 @@ def test_a_boolean_reform_target_is_not_a_number():
         "status": "ok",
         "years": [2027],
         "metrics": [
-            {"metric_id": f"reform_targets.{reform['id']}", "year": 2027, "value": True}
+            {
+                "metric_id": f"reform_targets.{reform['id']}",
+                "year": 2027,
+                "value": True,
+                **PUBLISHED,
+            }
         ],
         "identities": [
             {"identity_id": f"reform_runs:{reform['id']}", "status": "pass"},

From a2efd3614721cb71f085162bfd4815221418761c Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 04:08:33 -0400
Subject: [PATCH 41/45] Withhold population totals over fewer than 10 records
 from the ledger

supp-r3 on #574:

- Medium: the April rate-change row's 2027_total_change, summed over
  the people whose tax moved, was published even when only 1 to 9 of
  them moved, beside their suppressed counts. A total named in
  POPULATION_TOTALS is now published only when the counts of the
  records it sums over are whole counts adding up to 0 or 10 or more;
  any other number that is not a whole count (a total the runner adds
  later, a count written as a float) is withheld.
- Low: NumPy scalars became their text through json.dumps(default=str)
  and escaped suppression; _json_safe now turns them into the Python
  numbers they hold.
- Test gaps: the ledger evidence on pass, fail and error, for counts 0
  to 11 with NumPy and float counts; totals over 5, 9, 10 and 1,097
  records; the property test now hits 1, 9 and 10 often.
- Nits: equal exclusions need equal signs (docstring); one figure with
  two signs gets that reason in every section.

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                    |   2 +-
 src/policyengine/provenance/uk_candidate.py |  76 ++++++++++++---
 tests/test_uk_candidate_gates.py            | 101 +++++++++++++++++++-
 3 files changed, 162 insertions(+), 17 deletions(-)

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index d2bf789d..00a7fc8a 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. The ledger also never publishes a count from fewer than 10 records in the reform contract's population checks. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. The ledger also never publishes a count, or a total, from fewer than 10 records in the reform contract's population checks. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 00d19985..339040f5 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -53,8 +53,11 @@
 
 
 def _json_safe(value: Any) -> Any:
-    """Evidence as strict JSON: non-finite numbers become their names."""
+    """Evidence as strict JSON: NumPy scalars become the Python numbers they
+    hold (never their text), and non-finite numbers become their names."""
 
+    if type(value).__module__ == "numpy" and getattr(value, "ndim", None) == 0:
+        value = value.item()
     if isinstance(value, float) and not math.isfinite(value):
         return (
             "NaN" if math.isnan(value) else ("Infinity" if value > 0 else "-Infinity")
@@ -1290,20 +1293,62 @@ def reform_contract(
 #: aggregate-impact tool): a count of 1 to 9 units from the dataset is never
 #: published, and is written as this text instead.
 SUPPRESSED_COUNT = "fewer than 10"
+#: Written in place of a number the ledger does not publish.
+WITHHELD_VALUE = "withheld"
+
+#: Population detail values that are totals, with the counts of the records
+#: each sums over (``budget_reform_population`` in W1's runner). A total over
+#: 1 to 9 records is that handful's alone, so it is withheld with them.
+POPULATION_TOTALS: dict[str, tuple[str, ...]] = {
+    "2027_total_change": ("2027_people_with_lower_tax", "2027_people_with_higher_tax"),
+}
+
+
+def _is_count(value: Any) -> bool:
+    return isinstance(value, int) and not isinstance(value, bool)
 
 
 def _suppress_small_counts(value: Any) -> Any:
-    """``value`` with every integer count from 1 to 9, at any depth, replaced."""
+    """``value`` as the ledger may publish it: every whole count from 1 to 9,
+    at any depth, replaced by ``SUPPRESSED_COUNT``; every other number that is
+    not a whole count (a total, a count written as a float) replaced by
+    ``WITHHELD_VALUE``, since nothing says how many records it comes from."""
 
-    if isinstance(value, bool):
+    if isinstance(value, bool) or value is None or isinstance(value, str):
         return value
-    if isinstance(value, int) and 0 < value < 10:
-        return SUPPRESSED_COUNT
+    if _is_count(value):
+        return SUPPRESSED_COUNT if 0 < value < 10 else value
     if isinstance(value, Mapping):
         return {key: _suppress_small_counts(item) for key, item in value.items()}
     if isinstance(value, list):
         return [_suppress_small_counts(item) for item in value]
-    return value
+    return WITHHELD_VALUE
+
+
+def _publishable_detail(detail: Any) -> Any:
+    """A population row's ``detail`` as the ledger may publish it.
+
+    A total named in ``POPULATION_TOTALS`` is published only when the counts
+    of the records it sums over are whole counts that add up to 0 or at least
+    10; everything else follows ``_suppress_small_counts``, so a total the
+    runner adds later is withheld until it is listed here.
+    """
+
+    if not isinstance(detail, Mapping):
+        return _suppress_small_counts(detail)
+    published = {}
+    for key, value in detail.items():
+        if key in POPULATION_TOTALS and (
+            isinstance(value, (int, float)) and not isinstance(value, bool)
+        ):
+            counts = [detail.get(name) for name in POPULATION_TOTALS[key]]
+            safe = all(_is_count(count) for count in counts) and not (
+                0 < sum(counts) < 10
+            )
+            published[key] = value if safe else WITHHELD_VALUE
+        else:
+            published[key] = _suppress_small_counts(value)
+    return published
 
 
 def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
@@ -1311,15 +1356,17 @@ def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
 
     The ledger is a branch of a public repository. Case and property rows
     come from synthetic households, but population rows are computed on the
-    dataset, so a count of 1 to 9 in their ``detail`` (people whose tax fell,
-    payments that went down) is replaced by ``SUPPRESSED_COUNT``. The gate
-    judges the report as the runner returned it; no rule reads ``detail``.
+    dataset, so in their ``detail`` a count of 1 to 9 (people whose tax fell,
+    payments that went down) is replaced by ``SUPPRESSED_COUNT``, a total over
+    1 to 9 records and any number that is not a whole count are replaced by
+    ``WITHHELD_VALUE`` (``_publishable_detail``). The gate judges the report as
+    the runner returned it; no rule reads ``detail``.
     """
 
     published = dict(report)
     if isinstance(report.get("population"), list):
         published["population"] = [
-            {**row, "detail": _suppress_small_counts(row.get("detail"))}
+            {**row, "detail": _publishable_detail(row.get("detail"))}
             if isinstance(row, Mapping)
             else row
             for row in report["population"]
@@ -1593,7 +1640,8 @@ def compare_metric_reports(
     - a figure suppressed on one side only is withheld: no change is
       computed (it would come from fewer than 10 records) and the comparison
       needs review;
-    - a total compares directly when both sides exclude the same figures;
+    - a total compares directly when both sides exclude the same figures
+      with the same signs;
     - an additive total (``_additive``) whose sides exclude different
       figures is lined up as the tool's ``compare._aligned`` does: each side
       takes out, at its own published value and the excluding side's sign,
@@ -1793,9 +1841,7 @@ def compare_metric_reports(
             # definitions and could give an excluded figure back, so they are
             # lined up first, from published figures only, or withheld.
             reason = None
-            if not (_additive(row) and _additive(old)):
-                reason = "the reports leave out different suppressed figures"
-            elif any(
+            if any(
                 new_signs[metric_id] != old_signs[metric_id]
                 for metric_id in set(new_signs) & set(old_signs)
             ):
@@ -1803,6 +1849,8 @@ def compare_metric_reports(
                     "a figure both reports leave out enters their totals "
                     "with different signs"
                 )
+            elif not (_additive(row) and _additive(old)):
+                reason = "the reports leave out different suppressed figures"
             else:
                 lined_up = (
                     _aligned(new_value, row, old_signs, current, key[1]),
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 10f78680..252bd608 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -922,10 +922,99 @@ def test_the_ledger_never_publishes_a_small_count_from_the_dataset():
     }
 
 
+def _april_detail(lower, higher, total=1234.5):
+    return {
+        "2026_unchanged": True,
+        "2027_total_change": total,
+        "2027_people_with_lower_tax": lower,
+        "2027_people_with_higher_tax": higher,
+    }
+
+
+@pytest.mark.parametrize(
+    ("lower", "higher", "published"),
+    [
+        (2, 3, False),  # a total over five records (supp-r3 Medium 1)
+        (0, 9, False),
+        (4, 1093, True),  # the real run: 1,097 records
+        (0, 10, True),
+        (0, 0, True),  # over no records: nothing to give back
+    ],
+)
+def test_a_population_total_over_fewer_than_ten_records_is_withheld(
+    lower, higher, published
+):
+    from policyengine.provenance.uk_candidate import (
+        SUPPRESSED_COUNT,
+        WITHHELD_VALUE,
+        publishable_contract_report,
+    )
+
+    report = {"population": [{"detail": _april_detail(lower, higher)}]}
+    detail = publishable_contract_report(report)["population"][0]["detail"]
+    assert detail["2027_total_change"] == (1234.5 if published else WITHHELD_VALUE)
+    assert detail["2027_people_with_lower_tax"] == (
+        SUPPRESSED_COUNT if 0 < lower < 10 else lower
+    )
+    # A total whose counts are missing or not whole counts is withheld too.
+    broken = _april_detail(lower, float(higher))
+    detail = publishable_contract_report({"population": [{"detail": broken}]})
+    assert detail["population"][0]["detail"]["2027_total_change"] == WITHHELD_VALUE
+
+
+@pytest.mark.parametrize("outcome", ["pass", "fail", "error"])
+@pytest.mark.parametrize("count", range(12))
+def test_the_ledger_withholds_small_cells_whatever_the_gate_decides(outcome, count):
+    """supp-r3 S02, S11, S12: on a pass, a fail and an error alike, the
+    published evidence holds no count from 1 to 9 and no total over fewer
+    than 10 records, and its digest is the digest recorded. NumPy and float
+    counts (supp-r3 Low 2) are covered too. Values synthetic."""
+
+    import numpy as np
+
+    from policyengine.provenance.uk_candidate import SUPPRESSED_COUNT, WITHHELD_VALUE
+
+    report = _fixture("full_released_uk_2.130.1.json")
+    for row in report["population"]:
+        if row["check_id"] == "population_april_rate_change":
+            row["detail"] = _april_detail(np.int64(count), 0, total=777.25)
+        if row["check_id"] == "population_uc_standard_allowance_plus_10":
+            row["detail"]["payments_lower"] = float(count)
+    if outcome == "fail":
+        case = next(r for r in report["cases"] if r["status"] == "pass")
+        case["status"] = "fail"
+        report = _recount(report)
+    if outcome == "error":
+        report["seed"] = 1
+    result, evidence = _released_contract_outcome(report)
+    assert result.status == outcome, result.summary
+    april = [
+        row["detail"]
+        for row in evidence["population"]
+        if row["check_id"] == "population_april_rate_change"
+    ]
+    assert {d["2027_people_with_lower_tax"] for d in april} == {
+        SUPPRESSED_COUNT if 0 < count < 10 else count
+    }
+    assert {d["2027_total_change"] for d in april} == {
+        WITHHELD_VALUE if 0 < count < 10 else 777.25
+    }
+    uc = [
+        row["detail"]
+        for row in evidence["population"]
+        if row["check_id"] == "population_uc_standard_allowance_plus_10"
+    ]
+    assert {d["payments_lower"] for d in uc} == {WITHHELD_VALUE}
+    assert result.details["report_sha256"] == gates_module.evidence_sha256(evidence)
+    assert result.evidence_sha256 == gates_module.evidence_sha256(evidence)
+
+
 @settings(max_examples=200, deadline=None)
 @given(
     detail=st.recursive(
         st.one_of(
+            # The rule's edges come up often (supp-r3: 9 almost never did).
+            st.sampled_from([0, 1, 9, 10, 11]),
             st.integers(-20, 2000),
             st.booleans(),
             st.floats(allow_nan=False, allow_infinity=False),
@@ -942,6 +1031,7 @@ def test_the_ledger_never_publishes_a_small_count_from_the_dataset():
 def test_no_count_from_one_to_nine_survives_publication(detail):
     from policyengine.provenance.uk_candidate import (
         SUPPRESSED_COUNT,
+        WITHHELD_VALUE,
         publishable_contract_report,
     )
 
@@ -968,8 +1058,15 @@ def leaves(value):
     )
     assert len(before) == len(after)
     for old, new in zip(before, after):
-        small = not isinstance(old, bool) and isinstance(old, int) and 0 < old < 10
-        assert new == (SUPPRESSED_COUNT if small else old)
+        count = isinstance(old, int) and not isinstance(old, bool)
+        if count and 0 < old < 10:
+            assert new == SUPPRESSED_COUNT
+        elif isinstance(old, float):
+            # A number that is not a whole count: how many records it comes
+            # from is unknown (supp-r3).
+            assert new == WITHHELD_VALUE
+        else:
+            assert new == old
 
 
 @pytest.mark.parametrize("section", ["cases", "population"])

From d2aa8d482df06d01d50d5146df85d52c94c8a05f Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 04:50:33 -0400
Subject: [PATCH 42/45] Publish only true/false findings from population
 checks' details

supp-r4 on #574 found that the rows of one population check on
different routes share a subsample, so the difference between two
routes' published totals or counts is what a handful of records did,
and the same holds between two candidates (cos d1601). No per-value
rule can bound every combination, and no gate rule reads `detail`, so
the ledger now publishes each population row's check, route and status
and, from its detail, only its shape and true/false findings: every
count, total, amount and text is withheld. This replaces the per-value
suppression and the list of totals (and with them supp-r4's Low 1,
which came from trusting value types).

Also: NumPy unwrapping in evidence covers only bool, integer and
floating scalars, as the receipt does (supp-r4 nit), with a test that a
float32 NaN becomes "NaN" (J03); the sign-conflict reason is asserted
in every section (N01).

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                    |   2 +-
 src/policyengine/provenance/uk_candidate.py |  90 +++-----
 tests/fixtures/uk_contract/README.md        |   2 +-
 tests/test_uk_candidate_gates.py            | 215 +++++++++-----------
 4 files changed, 123 insertions(+), 186 deletions(-)

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index 00a7fc8a..afcbdb79 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. The ledger also never publishes a count, or a total, from fewer than 10 records in the reform contract's population checks. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. From the reform contract's population checks, which run on the survey data, the ledger publishes each row's check, route and status and only the true/false findings of its detail. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 339040f5..82a3c4d5 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -21,6 +21,7 @@
 import json
 import math
 import re
+import sys
 import traceback
 from collections import Counter
 from collections.abc import Callable, Iterable, Mapping, Sequence
@@ -56,7 +57,10 @@ def _json_safe(value: Any) -> Any:
     """Evidence as strict JSON: NumPy scalars become the Python numbers they
     hold (never their text), and non-finite numbers become their names."""
 
-    if type(value).__module__ == "numpy" and getattr(value, "ndim", None) == 0:
+    numpy = sys.modules.get("numpy")
+    if numpy is not None and isinstance(
+        value, (numpy.bool_, numpy.integer, numpy.floating)
+    ):
         value = value.item()
     if isinstance(value, float) and not math.isfinite(value):
         return (
@@ -1289,78 +1293,42 @@ def reform_contract(
     )
 
 
-#: The metrics tool's small-cell rule (``privacy.py`` in policyengine-uk's
-#: aggregate-impact tool): a count of 1 to 9 units from the dataset is never
-#: published, and is written as this text instead.
-SUPPRESSED_COUNT = "fewer than 10"
-#: Written in place of a number the ledger does not publish.
+#: Written in place of a value from the survey data that the ledger does
+#: not publish.
 WITHHELD_VALUE = "withheld"
 
-#: Population detail values that are totals, with the counts of the records
-#: each sums over (``budget_reform_population`` in W1's runner). A total over
-#: 1 to 9 records is that handful's alone, so it is withheld with them.
-POPULATION_TOTALS: dict[str, tuple[str, ...]] = {
-    "2027_total_change": ("2027_people_with_lower_tax", "2027_people_with_higher_tax"),
-}
-
-
-def _is_count(value: Any) -> bool:
-    return isinstance(value, int) and not isinstance(value, bool)
-
-
-def _suppress_small_counts(value: Any) -> Any:
-    """``value`` as the ledger may publish it: every whole count from 1 to 9,
-    at any depth, replaced by ``SUPPRESSED_COUNT``; every other number that is
-    not a whole count (a total, a count written as a float) replaced by
-    ``WITHHELD_VALUE``, since nothing says how many records it comes from."""
-
-    if isinstance(value, bool) or value is None or isinstance(value, str):
-        return value
-    if _is_count(value):
-        return SUPPRESSED_COUNT if 0 < value < 10 else value
-    if isinstance(value, Mapping):
-        return {key: _suppress_small_counts(item) for key, item in value.items()}
-    if isinstance(value, list):
-        return [_suppress_small_counts(item) for item in value]
-    return WITHHELD_VALUE
-
 
 def _publishable_detail(detail: Any) -> Any:
-    """A population row's ``detail`` as the ledger may publish it.
-
-    A total named in ``POPULATION_TOTALS`` is published only when the counts
-    of the records it sums over are whole counts that add up to 0 or at least
-    10; everything else follows ``_suppress_small_counts``, so a total the
-    runner adds later is withheld until it is listed here.
+    """A population row's ``detail`` as the ledger may publish it: its shape
+    and its true/false findings, with every other value withheld.
+
+    Population rows are computed on the survey data, and their numbers
+    combine: rows of one check on different routes share a subsample, so
+    two routes' totals or counts differ by what a handful of records did
+    (supp-r4 on #574), and two candidates' differ in the same way (cos
+    d1601). No per-value rule can bound every combination, and no gate rule
+    reads ``detail``, so nothing but ``True``, ``False`` and ``None`` is
+    published: not counts, totals, amounts or text.
     """
 
-    if not isinstance(detail, Mapping):
-        return _suppress_small_counts(detail)
-    published = {}
-    for key, value in detail.items():
-        if key in POPULATION_TOTALS and (
-            isinstance(value, (int, float)) and not isinstance(value, bool)
-        ):
-            counts = [detail.get(name) for name in POPULATION_TOTALS[key]]
-            safe = all(_is_count(count) for count in counts) and not (
-                0 < sum(counts) < 10
-            )
-            published[key] = value if safe else WITHHELD_VALUE
-        else:
-            published[key] = _suppress_small_counts(value)
-    return published
+    if isinstance(detail, bool) or detail is None:
+        return detail
+    if isinstance(detail, Mapping):
+        return {key: _publishable_detail(value) for key, value in detail.items()}
+    if isinstance(detail, list):
+        return [_publishable_detail(value) for value in detail]
+    return WITHHELD_VALUE
 
 
 def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
     """The reform contract report as the qualification ledger publishes it.
 
     The ledger is a branch of a public repository. Case and property rows
-    come from synthetic households, but population rows are computed on the
-    dataset, so in their ``detail`` a count of 1 to 9 (people whose tax fell,
-    payments that went down) is replaced by ``SUPPRESSED_COUNT``, a total over
-    1 to 9 records and any number that is not a whole count are replaced by
-    ``WITHHELD_VALUE`` (``_publishable_detail``). The gate judges the report as
-    the runner returned it; no rule reads ``detail``.
+    come from synthetic households and are published as reported. Population
+    rows are computed on the survey data, so their ``detail`` keeps only its
+    shape and true/false findings (``_publishable_detail``); their check,
+    route and status, which the gate judges, are published as reported. The
+    gate judges the report as the runner returned it.
     """
 
     published = dict(report)
diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index b3997b0b..a949276b 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -10,6 +10,6 @@ run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate
 
 The edits:
 - `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
-- Population rows are computed on the survey dataset, so a count from 1 to 9 in their `detail` is a small cell, which the metrics tool's `privacy.py` rule never publishes. In `full_released_uk_2.130.1.json`, `2027_people_with_lower_tax` and `payments_lower` (three rows each) are replaced by `"fewer than 10"`, as `publishable_contract_report` writes them to the qualification ledger. No gate rule reads `detail`. Check any new fixture for such counts before committing it.
+- Population rows are computed on the survey dataset, so a count from 1 to 9 in their `detail` is a small cell, which the metrics tool's `privacy.py` rule never publishes. In `full_released_uk_2.130.1.json`, `2027_people_with_lower_tax` and `payments_lower` (three rows each) are replaced by `"fewer than 10"`. No gate rule reads `detail`, and the qualification ledger (`publishable_contract_report`) publishes none of a population detail's values beyond true/false findings, since rows of one check on different routes share a subsample and their differences would give a handful's figures back. Check any new fixture for such counts before committing it.
 
 The run of contract 1.0.0 on policyengine-uk 2.126.8 (`full_allpass_uk_2.126.8.json`) was removed once no test read it.
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 252bd608..c46b53ab 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -892,94 +892,57 @@ def test_the_released_run_without_assertion_ids_resolves_by_oracle_and_order():
     assert result.details["counts"] == RELEASED_COUNTS
 
 
-def test_the_ledger_never_publishes_a_small_count_from_the_dataset():
-    """Round 10 of #574: population rows are computed on the survey data, so
-    a count from 1 to 9 in their detail is suppressed in the evidence the
-    ledger publishes, and the published digest is of that evidence, never
-    of the full report (whose digest would give the count back)."""
-
-    from policyengine.provenance.uk_candidate import SUPPRESSED_COUNT
-
-    report = _fixture("full_released_uk_2.130.1.json")
-    for row in report["population"]:
-        if row["check_id"] == "population_uc_standard_allowance_plus_10":
-            row["detail"]["payments_lower"] = 3  # synthetic small count
-    result, evidence = _released_contract_outcome(report)
-    assert result.status == "pass", result.summary
-    published = [
-        row["detail"]
-        for row in evidence["population"]
-        if row["check_id"] == "population_uc_standard_allowance_plus_10"
-    ]
-    assert {detail["payments_lower"] for detail in published} == {SUPPRESSED_COUNT}
-    assert {detail["payments_higher"] for detail in published} == {102}
-    assert {detail["awards_lower"] for detail in published} == {0}
-    assert result.details["report_sha256"] == gates_module.evidence_sha256(evidence)
-    assert result.evidence_sha256 == gates_module.evidence_sha256(evidence)
-    # Everything but the population details is published as reported.
-    assert {k: v for k, v in evidence.items() if k != "population"} == {
-        k: v for k, v in report.items() if k != "population"
-    }
-
-
-def _april_detail(lower, higher, total=1234.5):
-    return {
-        "2026_unchanged": True,
-        "2027_total_change": total,
-        "2027_people_with_lower_tax": lower,
-        "2027_people_with_higher_tax": higher,
-    }
+def _population_leaves(value):
+    if isinstance(value, dict):
+        for item in value.values():
+            yield from _population_leaves(item)
+    elif isinstance(value, list):
+        for item in value:
+            yield from _population_leaves(item)
+    else:
+        yield value
 
 
+@pytest.mark.parametrize("outcome", ["pass", "fail", "error"])
 @pytest.mark.parametrize(
-    ("lower", "higher", "published"),
-    [
-        (2, 3, False),  # a total over five records (supp-r3 Medium 1)
-        (0, 9, False),
-        (4, 1093, True),  # the real run: 1,097 records
-        (0, 10, True),
-        (0, 0, True),  # over no records: nothing to give back
-    ],
+    "variant", ["small counts", "routes differ", "numpy", "text and decimal"]
 )
-def test_a_population_total_over_fewer_than_ten_records_is_withheld(
-    lower, higher, published
-):
-    from policyengine.provenance.uk_candidate import (
-        SUPPRESSED_COUNT,
-        WITHHELD_VALUE,
-        publishable_contract_report,
-    )
+def test_the_ledger_publishes_no_value_from_the_survey_data(outcome, variant):
+    """Rounds 10, supp-r3 and supp-r4 of #574: population rows are computed on
+    the survey data, and their numbers combine (rows of one check on
+    different routes share a subsample, so their difference is a handful's),
+    so the published evidence keeps only each detail's shape and true/false
+    findings, on a pass, a fail and an error alike. Its digest is the digest
+    recorded, never one of the full report. Values synthetic."""
 
-    report = {"population": [{"detail": _april_detail(lower, higher)}]}
-    detail = publishable_contract_report(report)["population"][0]["detail"]
-    assert detail["2027_total_change"] == (1234.5 if published else WITHHELD_VALUE)
-    assert detail["2027_people_with_lower_tax"] == (
-        SUPPRESSED_COUNT if 0 < lower < 10 else lower
-    )
-    # A total whose counts are missing or not whole counts is withheld too.
-    broken = _april_detail(lower, float(higher))
-    detail = publishable_contract_report({"population": [{"detail": broken}]})
-    assert detail["population"][0]["detail"]["2027_total_change"] == WITHHELD_VALUE
-
-
-@pytest.mark.parametrize("outcome", ["pass", "fail", "error"])
-@pytest.mark.parametrize("count", range(12))
-def test_the_ledger_withholds_small_cells_whatever_the_gate_decides(outcome, count):
-    """supp-r3 S02, S11, S12: on a pass, a fail and an error alike, the
-    published evidence holds no count from 1 to 9 and no total over fewer
-    than 10 records, and its digest is the digest recorded. NumPy and float
-    counts (supp-r3 Low 2) are covered too. Values synthetic."""
+    from decimal import Decimal
 
     import numpy as np
 
-    from policyengine.provenance.uk_candidate import SUPPRESSED_COUNT, WITHHELD_VALUE
+    from policyengine.provenance.uk_candidate import WITHHELD_VALUE
 
     report = _fixture("full_released_uk_2.130.1.json")
-    for row in report["population"]:
-        if row["check_id"] == "population_april_rate_change":
-            row["detail"] = _april_detail(np.int64(count), 0, total=777.25)
-        if row["check_id"] == "population_uc_standard_allowance_plus_10":
-            row["detail"]["payments_lower"] = float(count)
+    april = [
+        r
+        for r in report["population"]
+        if r["check_id"] == "population_april_rate_change"
+    ]
+    for index, row in enumerate(april):
+        row["detail"] = {
+            "2026_unchanged": True,
+            "2027_total_change": 205573.0
+            + (index * 4321.0 if variant == "routes differ" else 0),
+            "2027_people_with_lower_tax": {
+                "small counts": 3,
+                "routes differ": 20,
+                "numpy": np.int64(4),
+                "text and decimal": "4",
+            }[variant],
+            "2027_people_with_higher_tax": (
+                Decimal(1093) if variant == "text and decimal" else 1093 + index * 4
+            ),
+            "nested": [{"count": 5, "ok": False}],
+        }
     if outcome == "fail":
         case = next(r for r in report["cases"] if r["status"] == "pass")
         case["status"] = "fail"
@@ -988,23 +951,31 @@ def test_the_ledger_withholds_small_cells_whatever_the_gate_decides(outcome, cou
         report["seed"] = 1
     result, evidence = _released_contract_outcome(report)
     assert result.status == outcome, result.summary
-    april = [
-        row["detail"]
-        for row in evidence["population"]
-        if row["check_id"] == "population_april_rate_change"
+    for row in evidence["population"]:
+        for leaf in _population_leaves(row.get("detail")):
+            assert leaf is None or isinstance(leaf, bool) or leaf == WITHHELD_VALUE, (
+                row["check_id"],
+                leaf,
+            )
+    published = [
+        r["detail"]
+        for r in evidence["population"]
+        if r["check_id"] == "population_april_rate_change"
     ]
-    assert {d["2027_people_with_lower_tax"] for d in april} == {
-        SUPPRESSED_COUNT if 0 < count < 10 else count
+    assert published[0] == {
+        "2026_unchanged": True,
+        "2027_total_change": WITHHELD_VALUE,
+        "2027_people_with_lower_tax": WITHHELD_VALUE,
+        "2027_people_with_higher_tax": WITHHELD_VALUE,
+        "nested": [{"count": WITHHELD_VALUE, "ok": False}],
     }
-    assert {d["2027_total_change"] for d in april} == {
-        WITHHELD_VALUE if 0 < count < 10 else 777.25
+    # What the gate judges is published as reported.
+    assert [
+        (r["check_id"], r["route"], r["status"]) for r in evidence["population"]
+    ] == [(r["check_id"], r["route"], r["status"]) for r in report["population"]]
+    assert {k: v for k, v in evidence.items() if k != "population"} == {
+        k: v for k, v in report.items() if k != "population"
     }
-    uc = [
-        row["detail"]
-        for row in evidence["population"]
-        if row["check_id"] == "population_uc_standard_allowance_plus_10"
-    ]
-    assert {d["payments_lower"] for d in uc} == {WITHHELD_VALUE}
     assert result.details["report_sha256"] == gates_module.evidence_sha256(evidence)
     assert result.evidence_sha256 == gates_module.evidence_sha256(evidence)
 
@@ -1013,8 +984,6 @@ def test_the_ledger_withholds_small_cells_whatever_the_gate_decides(outcome, cou
 @given(
     detail=st.recursive(
         st.one_of(
-            # The rule's edges come up often (supp-r3: 9 almost never did).
-            st.sampled_from([0, 1, 9, 10, 11]),
             st.integers(-20, 2000),
             st.booleans(),
             st.floats(allow_nan=False, allow_infinity=False),
@@ -1028,45 +997,21 @@ def test_the_ledger_withholds_small_cells_whatever_the_gate_decides(outcome, cou
         max_leaves=10,
     )
 )
-def test_no_count_from_one_to_nine_survives_publication(detail):
+def test_only_true_false_findings_survive_publication(detail):
     from policyengine.provenance.uk_candidate import (
-        SUPPRESSED_COUNT,
         WITHHELD_VALUE,
         publishable_contract_report,
     )
 
     report = {"cases": [{"detail": detail}], "population": [{"detail": detail}]}
     published = publishable_contract_report(report)
-
-    def leaves(value):
-        if isinstance(value, dict):
-            for item in value.values():
-                yield from leaves(item)
-        elif isinstance(value, list):
-            for item in value:
-                yield from leaves(item)
-        else:
-            yield value
-
-    for leaf in leaves(published["population"][0]["detail"]):
-        assert isinstance(leaf, bool) or not (isinstance(leaf, int) and 0 < leaf < 10)
-    # Synthetic case rows and every other value are left alone.
+    # Synthetic case rows are left alone.
     assert published["cases"] == report["cases"]
-    before, after = (
-        list(leaves(detail)),
-        list(leaves(published["population"][0]["detail"])),
-    )
+    before = list(_population_leaves(detail))
+    after = list(_population_leaves(published["population"][0]["detail"]))
     assert len(before) == len(after)
     for old, new in zip(before, after):
-        count = isinstance(old, int) and not isinstance(old, bool)
-        if count and 0 < old < 10:
-            assert new == SUPPRESSED_COUNT
-        elif isinstance(old, float):
-            # A number that is not a whole count: how many records it comes
-            # from is unknown (supp-r3).
-            assert new == WITHHELD_VALUE
-        else:
-            assert new == old
+        assert new == (old if old is None or isinstance(old, bool) else WITHHELD_VALUE)
 
 
 @pytest.mark.parametrize("section", ["cases", "population"])
@@ -2138,6 +2083,10 @@ def side(sign, value):
     assert evidence["moves_beyond_bounds"] == evidence["lined_up_totals"] == []
     (row,) = evidence["withheld_changes"]
     assert row["metric_id"] == "total"
+    # One figure with two signs says so in every section (supp-r4 N01).
+    assert row["reason"] == (
+        "a figure both reports leave out enters their totals with different signs"
+    )
     result, steps = metrics_review(
         candidate_report=candidate,
         previous_report=previous,
@@ -2369,6 +2318,26 @@ def test_a_report_that_breaks_the_small_cell_format_fails(mutate, message, side)
     assert f"the {side} report has" in summary and message in summary
 
 
+def test_numpy_scalars_in_evidence_become_the_numbers_they_hold():
+    """supp-r3 Low 2 and supp-r4 J03 and nit: NumPy bool, integer and float
+    scalars are unwrapped before the non-finite check (a float32 NaN is
+    "NaN", never an error); other NumPy values, such as a 0-d array or a
+    datetime64, are left for strict JSON to refuse."""
+
+    import numpy as np
+
+    safe = gates_module._json_safe
+    assert safe(np.int64(4)) == 4 and type(safe(np.int64(4))) is int
+    assert safe(np.bool_(True)) is True
+    assert safe(np.float32("nan")) == "NaN"
+    assert safe(np.float64("-inf")) == "-Infinity"
+    assert gates_module.evidence_sha256({"x": np.float32("nan")})
+    array = np.array(4)
+    assert safe(array) is array
+    stamp = np.datetime64("2026-10-16T00:00:00", "ns")
+    assert safe(stamp) is stamp
+
+
 def test_a_boolean_metric_value_is_not_a_number():
     report = _report(BASE)
     report["metrics"][0]["value"] = True

From 574e2625c22f7da26880ec68754a5f37524a6877 Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 06:30:11 -0400
Subject: [PATCH 43/45] Publish only population rows' fixed fields and
 top-level findings

supp-r5 on #574 (approved; lows):

- Population rows now publish only the runner's fixed fields
  (POPULATION_ROW_FIELDS: check, route, status, reason, seed, subsample
  size and the identity fields) as reported; any other field is
  withheld. From `detail`, only top-level True/False/None findings are
  kept, under the runner's own keys: a nested list or mapping is
  withheld whole, since its length or keys could be a count or name
  records.
- docs/engineering/runbooks/uk-qualification.md says what the ledger
  withholds and how to rerun a failed population check locally with
  access to the dataset, keeping its figures off the record.
- Tests: every non-detail field of every row published as reported
  (C04), an error row's status and withheld text (C07), a NaN total
  (P12), nested and list values withheld, and the property test on the
  top-level rule.

Co-Authored-By: Claude Opus 5.5 
---
 changelog.d/573.added.md                      |  2 +-
 docs/engineering/runbooks/uk-qualification.md | 51 ++++++++++++++
 src/policyengine/provenance/uk_candidate.py   | 62 ++++++++++++-----
 tests/fixtures/uk_contract/README.md          |  2 +-
 tests/test_uk_candidate_gates.py              | 66 ++++++++++++++++---
 5 files changed, 156 insertions(+), 27 deletions(-)
 create mode 100644 docs/engineering/runbooks/uk-qualification.md

diff --git a/changelog.d/573.added.md b/changelog.d/573.added.md
index afcbdb79..6d3d75c3 100644
--- a/changelog.d/573.added.md
+++ b/changelog.d/573.added.md
@@ -1 +1 @@
-Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. From the reform contract's population checks, which run on the survey data, the ledger publishes each row's check, route and status and only the true/false findings of its detail. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
+Qualify each new policyengine-uk wheel or uk-data release automatically before promotion. The new `certify-uk-release` workflow and `scripts/check_uk_candidate.py` resolve and deduplicate the candidate pair. They build a candidate commit with the manifest, pins, lock, TRO and test constants regenerated together, and run mandatory gates on it, none of which can be skipped: installed versions, wheel hashes, core compatibility, data access, dataset bytes, supported years, Budget inputs, the reform contract and metric review bounds. The metric review reads the aggregate-impact tool's small-cell format: a figure from fewer than 10 records is never compared, a change that would come from one goes to review, totals rebuilt without different suppressed figures are lined up from published figures where they are sums, a skipped check counts as not run, and only reports in that format are written to the ledger. From the reform contract's population checks, which run on the survey data, the ledger publishes each row's fixed fields (check, route, status and the like) and only the top-level true/false findings of its detail; `docs/engineering/runbooks/uk-qualification.md` explains how to see a failed check's figures locally. They also send policyengine-scorecard an immutable replay request, record a qualification receipt in the `uk-qualification-ledger` branch, and promote in order. Certification gains an exact `qualified_exact_pair` basis backed by the ledger receipt, together with a core compatibility check. The release dispatch now carries the certified UK bundle identity and goes to the Budget dashboard and the scorecard as well.
diff --git a/docs/engineering/runbooks/uk-qualification.md b/docs/engineering/runbooks/uk-qualification.md
new file mode 100644
index 00000000..bc04b9b3
--- /dev/null
+++ b/docs/engineering/runbooks/uk-qualification.md
@@ -0,0 +1,51 @@
+# UK candidate qualification: what the ledger shows, and reproducing a gate
+
+The `certify-uk-release` workflow qualifies each new policyengine-uk wheel
+or uk-data release before promotion (`scripts/check_uk_candidate.py`,
+`policyengine.provenance.uk_candidate`). Each attempt's gate results and
+evidence are written to the `uk-qualification-ledger` branch, which is
+public, so the evidence keeps nothing from the survey data that could
+identify a record.
+
+## What the ledger withholds
+
+- **Reform contract, population checks.** These run on the survey data. Each
+  row's check, route, status and the runner's fixed fields
+  (`POPULATION_ROW_FIELDS`) are published; from its `detail`, only top-level
+  `True`/`False`/`None` findings are kept, and every count, total, amount,
+  text, list or nested mapping reads `"withheld"`. The digest the gate
+  records is of that published copy, never of the full report.
+- **Metrics review and responsiveness.** The aggregate-impact tool publishes
+  a figure from fewer than 10 records as suppressed, and the gate records no
+  value from a report that breaks that format; such a report is published
+  only as its digest and problems.
+
+## Reproducing a failed population check
+
+The withheld figures exist only in the runner's report, which is not saved.
+To see them, rerun the contract on a machine with access to the private UK
+dataset, and keep the output local: it holds figures from the survey data,
+some from fewer than 10 records, so never commit, paste or publish it.
+
+1. Install the candidate pair (the attempt's `candidate.json` names the
+   wheels) and export `HUGGING_FACE_TOKEN` for the private dataset.
+2. Materialize the certified dataset and run the contract with the seed and
+   sample size in `src/policyengine/data/qualification/uk.json`:
+
+   ```python
+   from pathlib import Path
+
+   from policyengine.provenance.dataset_materialization import materialize_dataset
+   from policyengine.tax_benefit_models.uk.budget_reform_contract import (
+       run_budget_reform_contract,
+   )
+
+   dataset = materialize_dataset("uk", data_dir=Path("data")).path
+   report = run_budget_reform_contract(
+       routes=None, dataset_path=str(dataset), seed=0, max_examples=20
+   )
+   failing = [row for row in report["population"] if row["status"] != "pass"]
+   ```
+
+3. Read `failing[...]["detail"]` locally. Report only the finding (which
+   condition failed, on which route), never the figures.
diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index 82a3c4d5..a4fddc9c 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1298,26 +1298,46 @@ def reform_contract(
 WITHHELD_VALUE = "withheld"
 
 
+#: The population row fields W1's runner writes that carry no survey value
+#: (``budget_reform_population._row``, its identity fields and the run's
+#: fixed subsample size); they are published as reported. ``detail`` goes
+#: through ``_publishable_detail``; any other field is withheld.
+POPULATION_ROW_FIELDS = frozenset(
+    {
+        "check_id",
+        "route",
+        "status",
+        "reason",
+        "seed",
+        "subsample_households",
+        "reform_identity",
+        "reform_identity_unavailable",
+    }
+)
+
+
+def _finding(value: Any) -> Any:
+    return value if isinstance(value, bool) or value is None else WITHHELD_VALUE
+
+
 def _publishable_detail(detail: Any) -> Any:
-    """A population row's ``detail`` as the ledger may publish it: its shape
-    and its true/false findings, with every other value withheld.
+    """A population row's ``detail`` as the ledger may publish it: its
+    top-level true/false findings, with every other value withheld.
 
     Population rows are computed on the survey data, and their numbers
     combine: rows of one check on different routes share a subsample, so
     two routes' totals or counts differ by what a handful of records did
     (supp-r4 on #574), and two candidates' differ in the same way (cos
     d1601). No per-value rule can bound every combination, and no gate rule
-    reads ``detail``, so nothing but ``True``, ``False`` and ``None`` is
-    published: not counts, totals, amounts or text.
+    reads ``detail``. So only ``True``, ``False`` and ``None`` at the top of
+    a mapping are published, under the runner's own keys: not counts,
+    totals, amounts or text, and no nested list or mapping, whose length or
+    keys could be a count or name records (supp-r5).
     """
 
-    if isinstance(detail, bool) or detail is None:
-        return detail
-    if isinstance(detail, Mapping):
-        return {key: _publishable_detail(value) for key, value in detail.items()}
-    if isinstance(detail, list):
-        return [_publishable_detail(value) for value in detail]
-    return WITHHELD_VALUE
+    if not isinstance(detail, Mapping):
+        return _finding(detail)
+    return {key: _finding(value) for key, value in detail.items()}
 
 
 def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
@@ -1325,16 +1345,26 @@ def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
 
     The ledger is a branch of a public repository. Case and property rows
     come from synthetic households and are published as reported. Population
-    rows are computed on the survey data, so their ``detail`` keeps only its
-    shape and true/false findings (``_publishable_detail``); their check,
-    route and status, which the gate judges, are published as reported. The
-    gate judges the report as the runner returned it.
+    rows are computed on the survey data: the fields in
+    ``POPULATION_ROW_FIELDS`` (check, route and status, which the gate
+    judges, among them) are published as reported, ``detail`` keeps only its
+    top-level true/false findings (``_publishable_detail``), and any other
+    field is withheld. The gate judges the report as the runner returned it.
+    To see a failed population check's figures, rerun the contract with
+    access to the dataset (``docs/engineering/runbooks/uk-qualification.md``).
     """
 
     published = dict(report)
     if isinstance(report.get("population"), list):
         published["population"] = [
-            {**row, "detail": _publishable_detail(row.get("detail"))}
+            {
+                key: value
+                if key in POPULATION_ROW_FIELDS
+                else (
+                    _publishable_detail(value) if key == "detail" else _finding(value)
+                )
+                for key, value in row.items()
+            }
             if isinstance(row, Mapping)
             else row
             for row in report["population"]
diff --git a/tests/fixtures/uk_contract/README.md b/tests/fixtures/uk_contract/README.md
index a949276b..66867a1f 100644
--- a/tests/fixtures/uk_contract/README.md
+++ b/tests/fixtures/uk_contract/README.md
@@ -10,6 +10,6 @@ run on 11 October 2026. The qualification gate tests in `tests/test_uk_candidate
 
 The edits:
 - `dataset.path` (a local Hugging Face cache path) was replaced with a placeholder in the two files that name a dataset, and every file was re-serialized with sorted keys.
-- Population rows are computed on the survey dataset, so a count from 1 to 9 in their `detail` is a small cell, which the metrics tool's `privacy.py` rule never publishes. In `full_released_uk_2.130.1.json`, `2027_people_with_lower_tax` and `payments_lower` (three rows each) are replaced by `"fewer than 10"`. No gate rule reads `detail`, and the qualification ledger (`publishable_contract_report`) publishes none of a population detail's values beyond true/false findings, since rows of one check on different routes share a subsample and their differences would give a handful's figures back. Check any new fixture for such counts before committing it.
+- Population rows are computed on the survey dataset, so a count from 1 to 9 in their `detail` is a small cell, which the metrics tool's `privacy.py` rule never publishes. In `full_released_uk_2.130.1.json`, `2027_people_with_lower_tax` and `payments_lower` (three rows each) are replaced by `"fewer than 10"`. No gate rule reads `detail`, and the qualification ledger (`publishable_contract_report`) publishes none of a population detail's values beyond its top-level true/false findings, since rows of one check on different routes share a subsample and their differences would give a handful's figures back. Check any new fixture for such counts before committing it.
 
 The run of contract 1.0.0 on policyengine-uk 2.126.8 (`full_allpass_uk_2.126.8.json`) was removed once no test read it.
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index c46b53ab..6368eca4 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -942,6 +942,8 @@ def test_the_ledger_publishes_no_value_from_the_survey_data(outcome, variant):
                 Decimal(1093) if variant == "text and decimal" else 1093 + index * 4
             ),
             "nested": [{"count": 5, "ok": False}],
+            "names": ["income_tax:2027", "income_tax:2028"],
+            "total_nan": float("nan"),
         }
     if outcome == "fail":
         case = next(r for r in report["cases"] if r["status"] == "pass")
@@ -967,12 +969,16 @@ def test_the_ledger_publishes_no_value_from_the_survey_data(outcome, variant):
         "2027_total_change": WITHHELD_VALUE,
         "2027_people_with_lower_tax": WITHHELD_VALUE,
         "2027_people_with_higher_tax": WITHHELD_VALUE,
-        "nested": [{"count": WITHHELD_VALUE, "ok": False}],
+        # A nested list or mapping is withheld whole: its length or keys
+        # could be a count (supp-r5), and a NaN reads "withheld" too (P12).
+        "nested": WITHHELD_VALUE,
+        "names": WITHHELD_VALUE,
+        "total_nan": WITHHELD_VALUE,
     }
-    # What the gate judges is published as reported.
+    # Every field but the detail is published as reported (supp-r5 C04).
     assert [
-        (r["check_id"], r["route"], r["status"]) for r in evidence["population"]
-    ] == [(r["check_id"], r["route"], r["status"]) for r in report["population"]]
+        {k: v for k, v in r.items() if k != "detail"} for r in evidence["population"]
+    ] == [{k: v for k, v in r.items() if k != "detail"} for r in report["population"]]
     assert {k: v for k, v in evidence.items() if k != "population"} == {
         k: v for k, v in report.items() if k != "population"
     }
@@ -1007,11 +1013,53 @@ def test_only_true_false_findings_survive_publication(detail):
     published = publishable_contract_report(report)
     # Synthetic case rows are left alone.
     assert published["cases"] == report["cases"]
-    before = list(_population_leaves(detail))
-    after = list(_population_leaves(published["population"][0]["detail"]))
-    assert len(before) == len(after)
-    for old, new in zip(before, after):
-        assert new == (old if old is None or isinstance(old, bool) else WITHHELD_VALUE)
+
+    def finding(value):
+        return value if value is None or isinstance(value, bool) else WITHHELD_VALUE
+
+    expected = (
+        {key: finding(value) for key, value in detail.items()}
+        if isinstance(detail, dict)
+        else finding(detail)
+    )
+    assert published["population"][0]["detail"] == expected
+
+
+def test_population_rows_publish_only_the_runners_fixed_fields():
+    """supp-r5 C04 and C07: the runner's fixed fields, an error row's status
+    among them, are published as reported; any other field is withheld,
+    and an error row's text in its detail too. Values synthetic."""
+
+    from policyengine.provenance.uk_candidate import (
+        WITHHELD_VALUE,
+        publishable_contract_report,
+    )
+
+    fixed = {
+        "check_id": "population_april_rate_change",
+        "route": "country.reform_dict",
+        "status": "error",
+        "reason": None,
+        "seed": 0,
+        "subsample_households": 1000,
+        "reform_identity": None,
+        "reform_identity_unavailable": "population check rows are not bound to a reform identity",
+    }
+    row = {
+        **fixed,
+        "detail": "RuntimeError: total 1234.5 over 4 households\n",
+        "total_change": 1234.5,
+        "households": ["h1", "h2"],
+        "flag": True,
+    }
+    (published,) = publishable_contract_report({"population": [row]})["population"]
+    assert published == {
+        **fixed,
+        "detail": WITHHELD_VALUE,
+        "total_change": WITHHELD_VALUE,
+        "households": WITHHELD_VALUE,
+        "flag": True,
+    }
 
 
 @pytest.mark.parametrize("section", ["cases", "population"])

From 2ade4a0177c6e88dbc01620be789420ff71499ec Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 07:35:46 -0400
Subject: [PATCH 44/45] Runbook: rerun a population check on the attempt's own
 commit and data

Confirmation review of #574 (approved; Low 2): materialize_dataset fetches
the dataset the checked-out bundle manifest names, so following the
runbook from an older checkout would fetch older data even with the
candidate's wheels installed. The steps now check out harness.json's
git_commit first and check the dataset's SHA-256 against pair.json's
data.dataset_sha256 before running the contract.

Co-Authored-By: Claude Opus 5.5 
---
 docs/engineering/runbooks/uk-qualification.md | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/docs/engineering/runbooks/uk-qualification.md b/docs/engineering/runbooks/uk-qualification.md
index bc04b9b3..89306acb 100644
--- a/docs/engineering/runbooks/uk-qualification.md
+++ b/docs/engineering/runbooks/uk-qualification.md
@@ -27,12 +27,20 @@ To see them, rerun the contract on a machine with access to the private UK
 dataset, and keep the output local: it holds figures from the survey data,
 some from fewer than 10 records, so never commit, paste or publish it.
 
-1. Install the candidate pair (the attempt's `candidate.json` names the
+1. Check out the candidate commit the attempt ran on (`git_commit` in the
+   attempt's `harness.json` in the ledger): its bundle manifest names the
+   dataset `materialize_dataset` fetches, so an older checkout would fetch
+   older data even with the candidate's wheels installed.
+2. Install the candidate pair (the attempt's `candidate.json` names the
    wheels) and export `HUGGING_FACE_TOKEN` for the private dataset.
-2. Materialize the certified dataset and run the contract with the seed and
-   sample size in `src/policyengine/data/qualification/uk.json`:
+3. Materialize the certified dataset, check its SHA-256 against
+   `data.dataset_sha256` in the pair's `pair.json`, and run the contract
+   with the seed and sample size in
+   `src/policyengine/data/qualification/uk.json`:
 
    ```python
+   import hashlib
+   import json
    from pathlib import Path
 
    from policyengine.provenance.dataset_materialization import materialize_dataset
@@ -41,11 +49,14 @@ some from fewer than 10 records, so never commit, paste or publish it.
    )
 
    dataset = materialize_dataset("uk", data_dir=Path("data")).path
+   pair = json.loads(Path("path/to/ledger/uk//pair.json").read_text())
+   digest = hashlib.sha256(Path(dataset).read_bytes()).hexdigest()
+   assert digest == pair["data"]["dataset_sha256"], "not the certified dataset"
    report = run_budget_reform_contract(
        routes=None, dataset_path=str(dataset), seed=0, max_examples=20
    )
    failing = [row for row in report["population"] if row["status"] != "pass"]
    ```
 
-3. Read `failing[...]["detail"]` locally. Report only the finding (which
+4. Read `failing[...]["detail"]` locally. Report only the finding (which
    condition failed, on which route), never the figures.

From 5736f99d5763aaec75fe9d92cec2c324212c412d Mon Sep 17 00:00:00 2001
From: Max Ghenis 
Date: Fri, 16 Oct 2026 07:37:27 -0400
Subject: [PATCH 45/45] Withhold every population row field outside the
 runner's fixed set

Confirmation review of #574 (approved; Low 1): an unknown row field that
held true, false or None was published, while the docstrings and the
changelog say any field outside POPULATION_ROW_FIELDS is withheld. Its
name is not the runner's, so it is now withheld whatever its value. The
detail keys stay the runner's own, as documented.

Co-Authored-By: Claude Opus 5.5 
---
 src/policyengine/provenance/uk_candidate.py | 4 +---
 tests/test_uk_candidate_gates.py            | 6 ++++--
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/src/policyengine/provenance/uk_candidate.py b/src/policyengine/provenance/uk_candidate.py
index a4fddc9c..e77ec711 100644
--- a/src/policyengine/provenance/uk_candidate.py
+++ b/src/policyengine/provenance/uk_candidate.py
@@ -1360,9 +1360,7 @@ def publishable_contract_report(report: Mapping[str, Any]) -> dict[str, Any]:
             {
                 key: value
                 if key in POPULATION_ROW_FIELDS
-                else (
-                    _publishable_detail(value) if key == "detail" else _finding(value)
-                )
+                else (_publishable_detail(value) if key == "detail" else WITHHELD_VALUE)
                 for key, value in row.items()
             }
             if isinstance(row, Mapping)
diff --git a/tests/test_uk_candidate_gates.py b/tests/test_uk_candidate_gates.py
index 6368eca4..1f680dc2 100644
--- a/tests/test_uk_candidate_gates.py
+++ b/tests/test_uk_candidate_gates.py
@@ -1028,7 +1028,9 @@ def finding(value):
 def test_population_rows_publish_only_the_runners_fixed_fields():
     """supp-r5 C04 and C07: the runner's fixed fields, an error row's status
     among them, are published as reported; any other field is withheld,
-    and an error row's text in its detail too. Values synthetic."""
+    true/false ones included (the confirmation review: an unknown field's
+    name is not the runner's, so its finding is not published), and an
+    error row's text in its detail too. Values synthetic."""
 
     from policyengine.provenance.uk_candidate import (
         WITHHELD_VALUE,
@@ -1058,7 +1060,7 @@ def test_population_rows_publish_only_the_runners_fixed_fields():
         "detail": WITHHELD_VALUE,
         "total_change": WITHHELD_VALUE,
         "households": WITHHELD_VALUE,
-        "flag": True,
+        "flag": WITHHELD_VALUE,
     }