From d8b913d738426d8643e42ee9ed3664594276fb4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Sat, 17 Oct 2026 23:24:22 +0100 Subject: [PATCH 1/5] Let a leg of deferred cells stand without a control (#1301) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signing out the North East and Wales £2m region rows (485008810) left their local-authority cells, all deferred by the 400-home floor, on legs with no control. The small-cell rule adds such cells to the reconciliation frame to take their share of a region control, so the unparented-leg check then refused the surface: compile_uk_full_target_surface stopped on the abf0921 feed, and build 1 would have failed at uk.full.target_compilation. Nothing in CI compiles the full surface on the feed. The local surface now passes the reconciliation the area rows that bind nothing (its frame-only rows). A leg on which every open row is one of them and every target is licensed empty needs no control: it is receipted under deferred_legs_without_control instead of refused. A bound row on such a leg, a frame-only row without the licence, and a row of a target the leg is not licensed for are still orphans, as the Scottish authority of an England-only target is. Co-Authored-By: Claude Opus 5.5 --- .../1301-uk-local-solve-registers.changed.md | 2 +- .../src/microcosm/build/cross_grain.py | 93 +++++++++++++++++-- .../build/uk_runtime/ledger_targets.py | 14 +++ .../engine_free/shared/test_cross_grain.py | 67 +++++++++++++ 4 files changed, 167 insertions(+), 9 deletions(-) diff --git a/changelog.d/1301-uk-local-solve-registers.changed.md b/changelog.d/1301-uk-local-solve-registers.changed.md index 78cb73a71..228a26755 100644 --- a/changelog.d/1301-uk-local-solve-registers.changed.md +++ b/changelog.d/1301-uk-local-solve-registers.changed.md @@ -4,7 +4,7 @@ The registers that change the UK solve are in place before the first local relea **High-value homes.** The family's region rows control it on the local line, so: - `tools/generate_uk_local_target_references.py` defers its constituency level whole (`high_value_homes_constituency_grain_deferred`, `defer_if_compiles`), after the English band-H precedent, with a roster guard of 575 England and Wales constituencies; -- a new signed small-cell rule, `hvcts_la_household_floor` in `uk/local_small_cell_rule.json` (prefix `microcosm.high_value_homes.`, floor 400 homes, about two household weights at 150,000 households, expires 2027-04-01), defers the local-authority cells under the floor and keeps 192, 101 and 57 cells over £1m, £1.5m and £2m, whose deferred homes still count in their region rows. The two region rows below the floor, `microcosm.high_value_homes.over_2m_by_region` for the North East (`E12000001`) and Wales (`W92000004`), are signed out of the region fan-out by two row exclusions in `uk/target_reference_signed_exclusions.json` (María's ruling of 17 October 2026): their published stock is about one average household weight each at the ruled 150,000 households (an expectation from the stock, not a count of frame records), so their fit would be noise, and a public gate-only sign-off would narrow an estimate expected to rest on fewer than 10 records. A row-level signed exclusion can now name a geography cell (`row: {"dimension": "geography_id", ...}`). The same areas' £1m and £1.5m rows, which count those homes, stay bound; +- a new signed small-cell rule, `hvcts_la_household_floor` in `uk/local_small_cell_rule.json` (prefix `microcosm.high_value_homes.`, floor 400 homes, about two household weights at 150,000 households, expires 2027-04-01), defers the local-authority cells under the floor and keeps 192, 101 and 57 cells over £1m, £1.5m and £2m, whose deferred homes still count in their region rows. The two region rows below the floor, `microcosm.high_value_homes.over_2m_by_region` for the North East (`E12000001`) and Wales (`W92000004`), are signed out of the region fan-out by two row exclusions in `uk/target_reference_signed_exclusions.json` (María's ruling of 17 October 2026): their published stock is about one average household weight each at the ruled 150,000 households (an expectation from the stock, not a count of frame records), so their fit would be noise, and a public gate-only sign-off would narrow an estimate expected to rest on fewer than 10 records. A row-level signed exclusion can now name a geography cell (`row: {"dimension": "geography_id", ...}`). The same areas' £1m and £1.5m rows, which count those homes, stay bound. Their £2m authority cells are all deferred, so the cross-grain reconciliation now lets a leg that holds only the small-cell rule's deferred cells, of targets licensed empty there, stand without a control, receipted under `deferred_legs_without_control`; a bound row on such a leg is still refused as an orphan; - the `high_value_home_stock_derived_estimate` adjudication records where the family binds, and that the seat rank correlations, now out of sample, decide its renewal. **Islands.** Orkney (`local_authority/S12000023`) and Shetland (`local_authority/S12000027`) are pre-signed gate-only exclusions of the area-support floor in `uk/local_area_support_exclusions.json`, scoped to the local line and expiring 2027-01-16. Their cells stay bound. diff --git a/packages/microcosm-build/src/microcosm/build/cross_grain.py b/packages/microcosm-build/src/microcosm/build/cross_grain.py index 3a2dfd218..301f1e955 100644 --- a/packages/microcosm-build/src/microcosm/build/cross_grain.py +++ b/packages/microcosm-build/src/microcosm/build/cross_grain.py @@ -284,13 +284,19 @@ def _reconcile_cross_grain_surface_with_control_receipts( *, licensed_empty_legs: Mapping[str, frozenset[str]] | None = None, check_factor_bounds: bool = True, + frame_only_positions: frozenset[int] = frozenset(), ) -> tuple[ pd.DataFrame, list[dict[str, Any]], list[dict[str, Any]], list[dict[str, Any]], ]: - """Return a copied surface with every detected lower grain rescaled.""" + """Return a copied surface with every detected lower grain rescaled. + + ``frame_only_positions`` are rows that join the frame to take a share of + a control and bind nothing (a small-cell rule's deferred cells): a leg + holding only those, for targets licensed empty on it, needs no control. + """ columns = _surface_columns(local_frame) _validate_rule(rule) @@ -313,6 +319,7 @@ def _reconcile_cross_grain_surface_with_control_receipts( unparented_rows: dict[tuple[str, str], dict[int, str]] = {} first_pair_id: dict[tuple[str, str], str] = {} absent_middle_tier_legs: list[dict[str, Any]] = [] + deferred_legs_without_control: list[dict[str, Any]] = [] pairs_per_key: dict[tuple[str, str], int] = {} for group in materialized_groups: key = (group.inconsistency_id.rsplit(":", 1)[0], group.lower_grain) @@ -386,12 +393,24 @@ def _reconcile_cross_grain_surface_with_control_receipts( if last_pair_for_key and group.lower_grain not in control_grains: # No farther control can still claim these leaf rows: refuse now, # ahead of the empty-leg licence check, as the standing rule does. + # A leg only licensed-empty targets hold carries deferred cells + # alone and needs no control (_wholly_deferred_legs). + open_rows = { + position: leg + for position, leg in pending.items() + if position not in already and leg not in assigned_controls + } unparented = sorted( - { - leg - for position, leg in pending.items() - if position not in already and leg not in assigned_controls - } + set(open_rows.values()) + - set( + _wholly_deferred_legs( + open_rows, + reconciled, + columns, + licensed_empty_legs, + frame_only_positions, + ) + ) ) if unparented: raise ValueError( @@ -649,17 +668,30 @@ def _reconcile_cross_grain_surface_with_control_receipts( # A control-tier row with no control above it is the top of its # own leg, not an orphan. continue - still = { - leg + open_rows = { + position: leg for position, leg in pending.items() if position not in claimed[(identity, lower_grain)] } + deferred = _wholly_deferred_legs( + open_rows, reconciled, columns, licensed_empty_legs, frame_only_positions + ) + still = set(open_rows.values()) - set(deferred) if still: raise ValueError( f"cross-grain inconsistency " f"{first_pair_id[(identity, lower_grain)]!r} has " f"unparented lower-grain leg(s) {sorted(still)}." ) + deferred_legs_without_control.extend( + { + "inconsistency_id": first_pair_id[(identity, lower_grain)], + "lower_grain": lower_grain, + "leg": leg, + "lower_target_ids": list(target_ids), + } + for leg, target_ids in sorted(deferred.items()) + ) return ( reconciled, receipts, @@ -667,9 +699,47 @@ def _reconcile_cross_grain_surface_with_control_receipts( controls_without_lower_rows, delegated_legs, absent_middle_tier_legs, + deferred_legs_without_control, ) +def _wholly_deferred_legs( + rows: Mapping[int, str], + frame: pd.DataFrame, + columns: Mapping[str, str], + licensed_empty_legs: Mapping[str, frozenset[str]] | None, + frame_only_positions: frozenset[int], +) -> dict[str, tuple[str, ...]]: + """The legs of ``rows`` that hold deferred cells alone. + + A leg qualifies when every row on it is frame-only (it binds nothing and + joins the frame only to take its share of a control) and every target on + it is licensed empty there, so no cell of it binds on the leg. With no + control above them such rows have nothing to reconcile, and the leg is + no orphan (microcosm#1301: a region row signed out below the small-cell + floor leaves its wholly deferred authorities without one). A bound row, + or a row of a target the leg is not licensed for, keeps it an orphan. + """ + + targets_by_leg: dict[str, set[str]] = {} + bound_legs: set[str] = set() + for position, leg in rows.items(): + targets_by_leg.setdefault(leg, set()).add( + str(frame.iloc[position][columns["target_id"]]) + ) + if position not in frame_only_positions: + bound_legs.add(leg) + return { + leg: tuple(sorted(target_ids)) + for leg, target_ids in targets_by_leg.items() + if leg not in bound_legs + and all( + leg in _licensed_legs_for_target(target_id, licensed_empty_legs) + for target_id in target_ids + ) + } + + def reconcile_cross_grain_surface( local_frame: pd.DataFrame, groups: Iterable[CrossGrainInconsistency], @@ -699,12 +769,16 @@ def apply_cross_grain_reconciliation( reviewed_unbound_higher_targets: Mapping[str, Mapping[str, object]] | None = None, licensed_empty_legs: Mapping[str, frozenset[str]] | None = None, check_factor_bounds: bool = True, + frame_only_positions: Iterable[int] = (), ) -> tuple[pd.DataFrame, dict[str, Any]]: """Detect, reconcile, and return the always-present pass receipt. ``check_factor_bounds=False`` records each bounded bridge's factor without refusing it, for a pass that is not the caller's last (a surface whose off-surface cells join a second pass is bounded on that one). + ``frame_only_positions`` names the rows that bind nothing (deferred + cells); a leg holding only those needs no control + (``deferred_legs_without_control``). """ bound = tuple(str(target_id) for target_id in bound_higher_targets) @@ -728,12 +802,14 @@ def apply_cross_grain_reconciliation( controls_without_lower_rows, delegated_legs, absent_middle_tier_legs, + deferred_legs_without_control, ) = _reconcile_cross_grain_surface_with_control_receipts( local_frame, groups, rule, licensed_empty_legs=licensed_empty_legs, check_factor_bounds=check_factor_bounds, + frame_only_positions=frozenset(int(p) for p in frame_only_positions), ) receipt = { "bound_higher_targets": list(bound), @@ -745,6 +821,7 @@ def apply_cross_grain_reconciliation( "controls_without_lower_rows": controls_without_lower_rows, "delegated_legs": delegated_legs, "absent_middle_tier_legs": absent_middle_tier_legs, + "deferred_legs_without_control": deferred_legs_without_control, "absence": ( None if groups diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py index 36f96a328..b3f16fe42 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/ledger_targets.py @@ -1997,6 +1997,7 @@ def apply_uk_cross_grain_reconciliation( extra_bridges: Sequence[CrossGrainBridge] = (), extra_signatures: Mapping[str, Mapping[str, Any]] | None = None, check_factor_bounds: bool = True, + frame_only_positions: Iterable[int] = (), ) -> tuple[pd.DataFrame, dict[str, Any]]: """Apply the standing UK rule to a bound mixed-grain target surface. @@ -2004,6 +2005,9 @@ def apply_uk_cross_grain_reconciliation( controls the joint surface adds for its declared fan-out sum bridges. ``check_factor_bounds=False`` records the bridges' factor bounds without refusing, for a pass the caller reruns with more rows. + ``frame_only_positions`` names the rows that bind nothing (the small-cell + rule's deferred cells), so a wholly deferred leg with no control above it + is receipted rather than refused (microcosm#1301). Increment #762 may extend the grains in the UK rowwise solve only through this front door, so detection, reconciliation, and the manifest receipt @@ -2040,6 +2044,7 @@ def apply_uk_cross_grain_reconciliation( reviewed_unbound_higher_targets=reviewed_unbound_higher_targets, licensed_empty_legs=licences, check_factor_bounds=check_factor_bounds, + frame_only_positions=frame_only_positions, ) @@ -2741,6 +2746,14 @@ def reconcile( columns=["grain", "geography_id", "target_id", "value", "_output_position"], ) raw = frame[["grain", "geography_id", "target_id", "value"]] + # The area rows that bind nothing (deferred and off-surface cells): a + # leg holding only deferred ones needs no control (microcosm#1301). + frame_only = [ + position + for position, row in enumerate(reconciliation_rows) + if row["_output_position"] is None + and row["grain"] in level_to_area_type.values() + ] result, pass_receipt = apply_uk_cross_grain_reconciliation( raw, bound_control_ids, @@ -2750,6 +2763,7 @@ def reconcile( extra_bridges=fanout_bridges, extra_signatures=fanout_signatures, check_factor_bounds=check_factor_bounds, + frame_only_positions=frame_only, ) return frame, raw, result, pass_receipt diff --git a/packages/microcosm-build/tests/engine_free/shared/test_cross_grain.py b/packages/microcosm-build/tests/engine_free/shared/test_cross_grain.py index 3723e65bd..6b50bc315 100644 --- a/packages/microcosm-build/tests/engine_free/shared/test_cross_grain.py +++ b/packages/microcosm-build/tests/engine_free/shared/test_cross_grain.py @@ -400,6 +400,7 @@ def test_absence_receipt_exists_when_no_higher_target_is_bound(): "controls_without_lower_rows": [], "delegated_legs": [], "absent_middle_tier_legs": [], + "deferred_legs_without_control": [], "absence": "No cross-grain inconsistencies are in force on this surface.", } @@ -597,6 +598,72 @@ def test_unparented_and_empty_legs_are_refused(): apply_cross_grain_reconciliation(empty, ("national",), signatures, _rule()) +def test_a_leg_holding_only_deferred_cells_needs_no_control(): + """Frame-only rows of a target licensed empty on their leg are deferred + cells: with no control above them they are receipted, not refused. A + bound row there, a frame-only row without the licence, or a licensed + row that binds is still an orphan (microcosm#1301).""" + + surface = pd.DataFrame( + [ + ("country", "E", "national", 10.0), + ("constituency", "E1", "local", 10.0), + ("constituency", "N1", "local", 3.0), + ], + columns=["grain", "geography_id", "target_id", "value"], + ) + signatures = { + target_id: _signature() for target_id in ("national", "local", "bound") + } + licences = {"local": frozenset({"N"})} + + reconciled, receipt = apply_cross_grain_reconciliation( + surface, + ("national",), + signatures, + _rule(), + licensed_empty_legs=licences, + frame_only_positions=(2,), + ) + + assert reconciled["value"].tolist() == [10.0, 10.0, 3.0] + assert receipt["deferred_legs_without_control"] == [ + { + "inconsistency_id": receipt["groups"][0]["inconsistency_id"], + "lower_grain": "constituency", + "leg": "N", + "lower_target_ids": ["local"], + } + ] + + with_bound = pd.concat( + [ + surface, + pd.DataFrame( + [("constituency", "N2", "bound", 2.0)], columns=surface.columns + ), + ], + ignore_index=True, + ) + with pytest.raises(ValueError, match=r"unparented lower-grain leg\(s\) \['N'\]"): + apply_cross_grain_reconciliation( + with_bound, + ("national",), + signatures, + _rule(), + licensed_empty_legs=licences, + frame_only_positions=(2,), + ) + for kwargs in ( + {"frame_only_positions": (2,)}, + {"licensed_empty_legs": licences}, + ): + with pytest.raises(ValueError, match="unparented"): + apply_cross_grain_reconciliation( + surface, ("national",), signatures, _rule(), **kwargs + ) + + def test_empty_leg_licensed_for_every_lower_target_is_receipted_and_skipped(): surface = pd.DataFrame( [ From d0f0fafec74080bc9a12b8b22ba57762872be8fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Thu, 15 Oct 2026 14:04:45 +0100 Subject: [PATCH 2/5] Renew the ONS D.41 savings-interest diagnostic exclusion to 2027-01-08 (#866) The ons.savings_interest_income measure exclusion lapses on 2026-10-22. After that date no national calibration could run, since the window is checked when the exclusions are applied, and the dense two-build flow's gate clock and assembly deadline stop there too. The row stays a measured diagnostic and is never fitted, as ruling R3 of 2026-09-22 set: the ONS D.41 row is a national-accounts concept, while the model carries cash interest, and the SPI interest rows are the fitting anchor. Renewed by juaristi22 on 2026-10-16 in the sixth #1095 ports PR (#1308), and shipped here ahead of it, unchanged, so that the first local release build stands on it; #1308's re-review recommended shipping it alone. The packaged-exclusions test pins the new window and the renewal note, and the 2026-10-16 approvals are now the employer NICs diagnostic and this. Co-Authored-By: Claude Opus 5.5 --- ...866-savings-interest-diagnostic-renewal.changed.md | 1 + .../build/uk/calibration_measure_exclusions.json | 6 +++--- .../engine_free/uk/test_uk_measure_simulation.py | 11 +++++++---- 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 changelog.d/866-savings-interest-diagnostic-renewal.changed.md diff --git a/changelog.d/866-savings-interest-diagnostic-renewal.changed.md b/changelog.d/866-savings-interest-diagnostic-renewal.changed.md new file mode 100644 index 000000000..c9e76ffb2 --- /dev/null +++ b/changelog.d/866-savings-interest-diagnostic-renewal.changed.md @@ -0,0 +1 @@ +The `ons.savings_interest_income` measure exclusion is renewed to 2027-01-08 (microcosm#866; renewed by juaristi22 on 2026-10-16): the ONS D.41 interest row stays a measured diagnostic and is never fitted, as ruling R3 of 2026-09-22 set, because its concept differs from the model's cash interest. Without the renewal it lapsed on 2026-10-22, and no national calibration could run after that date. diff --git a/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json b/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json index b74314e4d..9b7341dff 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json +++ b/packages/microcosm-build/src/microcosm/build/uk/calibration_measure_exclusions.json @@ -285,9 +285,9 @@ "reason": "Concept, not a weight question: the ONS UKEA HAXV row is households' (S.14) D.41 interest resources in the national accounts (FISIM-adjusted, including the unincorporated-business part of the sector; GBP 95.5bn at 2025) while the model's savings_interest_income is cash interest, so the row is unreachable by design (-82 percent on the v20 national candidate). From 2026-09-22 the fitting anchor for interest is the SPI 2023-24 Table 3.7 interest rows by total-income band, uprated to the calibration year (hmrc.spi.savings_interest_income.*, PolicyEngine/chronicle#280 lane); this row is measured on every evaluation as the D.41 diagnostic and never fitted. Retire only with a declared D.41-to-cash bridge.", "tracking": "microcosm#866", "approved_by": "juaristi22", - "adjudication": "PolicyEngine/microcosm#1006 (issue comment 5812206367, the register rulings María gave in session: ruling R3 of 2026-09-22, the SPI interest rows bound and the ONS row a measured diagnostic; income-anchor lane, PolicyEngine/chronicle#280); previously microcosm#762 A16 (2026-09-03).", - "approved_on": "2026-09-22", - "expires_on": "2026-10-22" + "adjudication": "PolicyEngine/microcosm#1006 (issue comment 5812206367, the register rulings María gave in session: ruling R3 of 2026-09-22, the SPI interest rows bound and the ONS row a measured diagnostic; income-anchor lane, PolicyEngine/chronicle#280); previously microcosm#762 A16 (2026-09-03); renewed on 2026-10-16 to 2027-01-08 by juaristi22 in session (folded into the sixth microcosm#1095 ports PR): the gap is one of concept, not of weights, so the row stays a measured diagnostic until a D.41-to-cash bridge is declared.", + "approved_on": "2026-10-16", + "expires_on": "2027-01-08" }, { "name": "obr.housing_benefit", diff --git a/packages/microcosm-build/tests/engine_free/uk/test_uk_measure_simulation.py b/packages/microcosm-build/tests/engine_free/uk/test_uk_measure_simulation.py index f11d51a9f..c1a502846 100644 --- a/packages/microcosm-build/tests/engine_free/uk/test_uk_measure_simulation.py +++ b/packages/microcosm-build/tests/engine_free/uk/test_uk_measure_simulation.py @@ -785,10 +785,11 @@ def test_packaged_exclusions_load(): # microcosm#1095: the five-or-more children row held out on 2026-10-14 # (María's ruling on microcosm#1271) is no target since 2026-10-16, but a # diagnostic beside the two-child-limit rows, so no exclusion names it and - # only the housing-element renewal carries that date. + # only the housing-element renewal carries that date. The 2026-10-16 + # entries are the employer NICs diagnostic and the savings-interest renewal. assert sorted( e["name"] for e in exclusions if e["approved_on"] == "2026-10-16" - ) == ["obr.ni_employer"] + ) == ["obr.ni_employer", "ons.savings_interest_income"] assert sorted( e["name"] for e in exclusions if e["approved_on"] == "2026-10-14" ) == sorted(_UC_ELEMENT_REGISTER_ROWS) @@ -806,10 +807,12 @@ def test_packaged_exclusions_load(): assert entry["tracking"] == a16_issues[name], name for name in _A16_CONCEPT_ROWS: entry = next(e for e in exclusions if e["name"] == name) - assert entry["approved_on"] == "2026-09-22", name - assert entry["expires_on"] == "2026-10-22", name + # Ruling R3 of 2026-09-22, renewed on 2026-10-16 to 2027-01-08. + assert entry["approved_on"] == "2026-10-16", name + assert entry["expires_on"] == "2027-01-08", name assert entry["tracking"] == a16_issues[name], name assert "microcosm#1006" in entry["adjudication"], name + assert "renewed on 2026-10-16" in entry["adjudication"], name assert "D.41" in entry["reason"] and "diagnostic" in entry["reason"], name # The fitting anchor the row hands over to: the SPI Table 3.7 interest # rows, uprated (PolicyEngine/chronicle#280 lane). From 07d6b43e7a4be708d338ebe76cd22fcb96259a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Sun, 18 Oct 2026 16:06:28 +0100 Subject: [PATCH 3/5] Allow the high-value homes support columns on the UK export surface (#1301) The first dense release build (microcosm#1301, attempt 1f0939c4) failed uk_export_surface on three household columns outside the incumbent surface with no allow-list entry: high_value_support_copies, high_value_support_copy_index and household_is_high_value_support_copy. They are the microcosm#1240 high-value homes support split's declared outputs (the release input coverage manifest lists them), the exact analog of the CGT support split's three columns, which the list already carries. microcosm#1270 added the stage but not the allow-list entries, so every UK build since then fails the gate at the calibrated battery. Add them to gates.json and UK_ALLOWED_EXTRA_EXPORT_COLUMNS in the same place as the CGT split's columns. The gate fails only on missing or unexpected columns, so a line that does not carry them is unaffected. Re-pin the full gate battery's policy, gates-manifest and spec digests and the release-cut part's digests; the spine, calibration-seam and dense digests do not move, so existing spines stay valid. gates.json is in the solve fingerprint, so the next dense build re-solves. Co-Authored-By: Claude Opus 5.5 --- .../1301-uk-export-surface-high-value-support.fixed.md | 1 + .../microcosm-build/src/microcosm/build/uk/gates.json | 3 +++ .../src/microcosm/build/uk_runtime/terminal_gates.py | 7 +++++++ packages/microcosm-data/src/microcosm/data/contract.py | 10 +++++----- .../tests/engine_free/shared/test_contract.py | 6 +++--- 5 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 changelog.d/1301-uk-export-surface-high-value-support.fixed.md diff --git a/changelog.d/1301-uk-export-surface-high-value-support.fixed.md b/changelog.d/1301-uk-export-surface-high-value-support.fixed.md new file mode 100644 index 000000000..31f4978f2 --- /dev/null +++ b/changelog.d/1301-uk-export-surface-high-value-support.fixed.md @@ -0,0 +1 @@ +The UK export-surface gate's allow-list carries the high-value homes support split's three household columns (`high_value_support_copies`, `high_value_support_copy_index` and `household_is_high_value_support_copy`, microcosm#1240), beside the CGT support split's precedent, in `gates.json` and `UK_ALLOWED_EXTRA_EXPORT_COLUMNS` alike. They are the stage's declared coverage-manifest outputs. Without them every UK build since microcosm#1270 fails `uk_export_surface` at the calibrated gates, and the first dense release build (microcosm#1301) did; that gate has no gate-only register, so the fix changes the solve's key and the next build re-solves. The full gate battery's policy, gates-manifest and spec digests and the release-cut part's digests are re-pinned; the spine, calibration-seam and dense digests do not move. diff --git a/packages/microcosm-build/src/microcosm/build/uk/gates.json b/packages/microcosm-build/src/microcosm/build/uk/gates.json index cea2637b2..aae6d2be7 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/gates.json +++ b/packages/microcosm-build/src/microcosm/build/uk/gates.json @@ -953,6 +953,9 @@ "household.cash_isa", "household.cgt_support_copies", "household.cgt_support_copy_index", + "household.high_value_support_copies", + "household.high_value_support_copy_index", + "household.household_is_high_value_support_copy", "household.household_is_cgt_residential_clone", "household.cgt_residential_clone_index", "household.household_clone_index", diff --git a/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py b/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py index 7f48ee938..09c09006d 100644 --- a/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py +++ b/packages/microcosm-build/src/microcosm/build/uk_runtime/terminal_gates.py @@ -182,6 +182,13 @@ def __post_init__(self) -> None: # #1045: the CGT support split's family copy count. "household.cgt_support_copies", "household.cgt_support_copy_index", + # microcosm#1240: the high-value homes support split's family copy count, + # index and flag, the CGT split's precedent. The stage's coverage-manifest + # outputs; the first dense release build failed this gate on them + # (microcosm#1301). + "household.high_value_support_copies", + "household.high_value_support_copy_index", + "household.household_is_high_value_support_copy", # #1063: the residential split's arm flag and index. "household.household_is_cgt_residential_clone", "household.cgt_residential_clone_index", diff --git a/packages/microcosm-data/src/microcosm/data/contract.py b/packages/microcosm-data/src/microcosm/data/contract.py index 971f65158..38f8118a4 100644 --- a/packages/microcosm-data/src/microcosm/data/contract.py +++ b/packages/microcosm-data/src/microcosm/data/contract.py @@ -447,13 +447,13 @@ def compatibility_claim_declarer_error(declared_by: object) -> str | None: # fingerprint derives from the manifest digest. Editing the spec moves all # three here in the same reviewed change. _UK_GATE_BATTERY_POLICY_SHA256 = ( - "575039e9d1876fbf3732fc30ae05b19c13160550a507aa8cad4f6301d050b896" + "1e6c3da7cba654da5b0244affa6f2696369ced8464cc47d831e37f5c9fd76377" ) _UK_GATE_BATTERY_GATES_MANIFEST_SHA256 = ( - "445a09e59c2cea85bb6b3e7dc160465c9ca4a3b7da7d525201c0b4730ff7a663" + "3efc24780ea8e3961f36ee526de69048ed2198285e738a65d82f0fda13080cd1" ) _UK_GATE_BATTERY_SPEC_FINGERPRINT = ( - "f84643ec1f55f85ddff61fe0b65beba1b29478378212aa161d055341b86dad43" + "1a6e57d5e889f4c62297c283a041a917dcaa025dce129eee38ae126ffcb37233" ) #: Spec entry id -> the legacy gate name whose observable detail checks #: apply unchanged (the battery re-keys the report by entry id; the gate @@ -939,10 +939,10 @@ def _uk_line_cut_tag_re(release_id: str) -> re.Pattern[str] | None: }, "release_cut": { "gates_manifest_sha256": ( - "507b7f7482b128dba12fe67b8451143d2a9a3774339c0c016b7c7cc2ff5262ab" + "778e1a26f58b2f1347c0438321117da905e6ff1f5902468c1fe24a186cd5b891" ), "policy_sha256": ( - "c3c8622ec081579ad280fadb3c6e58515457cb8a3f114c8fd6a4ca19490d2b20" + "3a1dd5dfae4cd52de9d71f3f3542e67758c5e73862fde88b0b97e040d5d46396" ), }, } diff --git a/packages/microcosm-data/tests/engine_free/shared/test_contract.py b/packages/microcosm-data/tests/engine_free/shared/test_contract.py index d8e7e1851..98510cca0 100644 --- a/packages/microcosm-data/tests/engine_free/shared/test_contract.py +++ b/packages/microcosm-data/tests/engine_free/shared/test_contract.py @@ -213,13 +213,13 @@ def _trusted_terminal_gate_signing_key(monkeypatch) -> None: UK_GATE_BATTERY_PRODUCER = "microcosm.build.gate_battery" UK_GATE_BATTERY_SIGNING_KEY_ENV = "MICROCOSM_UK_TERMINAL_GATE_SIGNING_KEY" UK_GATE_BATTERY_POLICY_SHA256 = ( - "575039e9d1876fbf3732fc30ae05b19c13160550a507aa8cad4f6301d050b896" + "1e6c3da7cba654da5b0244affa6f2696369ced8464cc47d831e37f5c9fd76377" ) UK_GATE_BATTERY_GATES_MANIFEST_SHA256 = ( - "445a09e59c2cea85bb6b3e7dc160465c9ca4a3b7da7d525201c0b4730ff7a663" + "3efc24780ea8e3961f36ee526de69048ed2198285e738a65d82f0fda13080cd1" ) UK_GATE_BATTERY_SPEC_FINGERPRINT = ( - "f84643ec1f55f85ddff61fe0b65beba1b29478378212aa161d055341b86dad43" + "1a6e57d5e889f4c62297c283a041a917dcaa025dce129eee38ae126ffcb37233" ) UK_GATE_BATTERY_DEGENERATE_EVIDENCE_SHA256 = ( "6a179222c6b6058ad9caacfd347f7bdb8cb98a62237b50d1fc1136df09337251" From 356dc4f7f7097e5f2877d99789cd3999de163b75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:52:32 +0100 Subject: [PATCH 4/5] Round-trip the committed pins with their own local-line scope (#1301) test_the_committed_pins_rewrite_and_reparse rewrote every committed pin back with local_only=False, which held only while the gate-only registers were empty. The drafter adds the local-line scope pin whenever every entry of a register is local-only, so the first real sign-off's pins lost that line on the way back and the test failed. Rewrite back with the scope the committed register has, as the drafter decides it. Co-Authored-By: Claude Opus 5.5 --- .../engine_free/uk/test_uk_dense_signoff_draft.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/microcosm-build/tests/engine_free/uk/test_uk_dense_signoff_draft.py b/packages/microcosm-build/tests/engine_free/uk/test_uk_dense_signoff_draft.py index e54db407e..fdc2a21cf 100644 --- a/packages/microcosm-build/tests/engine_free/uk/test_uk_dense_signoff_draft.py +++ b/packages/microcosm-build/tests/engine_free/uk/test_uk_dense_signoff_draft.py @@ -2141,12 +2141,18 @@ def test_the_committed_pins_are_found(): def test_the_committed_pins_rewrite_and_reparse(): # Each committed pin takes a drafted key set in place, with or without - # the local-line scope pin, and gives the committed one back. + # the local-line scope pin, and gives the committed one back. The committed + # pin carries the scope pin when every committed entry is local-only, as + # the drafter writes it, so a signed register round-trips too. for spec in TOOL.REGISTERS: if spec.loader is None: continue payload = json.loads((REPOSITORY / spec.path).read_text(encoding="utf-8")) committed = sorted(payload[spec.block]) + committed_local_only = bool(committed) and all( + tuple(entry.get("release_lines") or ()) == (TOOL.LOCAL_LINE,) + for entry in payload[spec.block].values() + ) for relative in TOOL.PIN_SEARCH: source = (REPOSITORY / relative).read_text(encoding="utf-8") if not TOOL.find_pins(source, spec.loader, spec.pin_block): @@ -2167,7 +2173,7 @@ def test_the_committed_pins_rewrite_and_reparse(): drafted, spec.loader, committed, - local_only=False, + local_only=committed_local_only, block=spec.pin_block, ) assert back == source, (spec.gate_id, relative) From 810315ac22b81c15c008cfb2723ee99e18725fe4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mar=C3=ADa=20Juaristi?= <127882282+juaristi22@users.noreply.github.com> Date: Mon, 19 Oct 2026 00:52:32 +0100 Subject: [PATCH 5/5] Sign the measured local release build's gate-only failures (#1301) The second dense build (attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89, at 07d6b43e7) was blocked only by gate-only failures. This is tools/draft_uk_dense_signoff.py's patch from that run, unchanged except the changelog's wording: 15 national target-fit rows, 31 local target-fit cells and 2 areas below the support floor, every entry scoped to the local line, approved by juaristi22 on 2026-10-19; fit entries expire on 2026-11-16 and area entries on 2027-01-19. The registers' key-set pins move with them. Every signed row stays bound in the solve, and the reuse build fails any entry whose row passes as stale. Co-Authored-By: Claude Opus 5.5 --- ...301-uk-dense-signoff-2026-10-19.changed.md | 1 + .../uk/local_area_support_exclusions.json | 20 ++ .../local_target_fit_reviewed_exclusions.json | 313 +++++++++++++++++- .../uk/target_fit_reviewed_exclusions.json | 153 ++++++++- .../engine_free/uk/test_uk_terminal_gates.py | 54 ++- .../uk/test_uk_weighted_integrity.py | 2 + 6 files changed, 539 insertions(+), 4 deletions(-) create mode 100644 changelog.d/1301-uk-dense-signoff-2026-10-19.changed.md diff --git a/changelog.d/1301-uk-dense-signoff-2026-10-19.changed.md b/changelog.d/1301-uk-dense-signoff-2026-10-19.changed.md new file mode 100644 index 000000000..db1bfe033 --- /dev/null +++ b/changelog.d/1301-uk-dense-signoff-2026-10-19.changed.md @@ -0,0 +1 @@ +Sign the measured local release build's gate-only failures for the local line (microcosm#1301; the second dense build, attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89, after the first failed `uk_export_surface`, which microcosm#1310 fixed): 15 national target-fit rows, 31 local target-fit cells and 2 areas below the support floor, approved 2026-10-19; no entry that the reuse build would fail needed retiring. Every signed row stays bound in the solve, each entry suppresses only the local line's release fence, and a build in which a signed row passes fails its entry as stale. The sign-off draft's pin round-trip test now restores a committed pin's local-line scope, which it lost once every entry of a register was local-only. diff --git a/packages/microcosm-build/src/microcosm/build/uk/local_area_support_exclusions.json b/packages/microcosm-build/src/microcosm/build/uk/local_area_support_exclusions.json index 3b2f9bfde..17afaa478 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/local_area_support_exclusions.json +++ b/packages/microcosm-build/src/microcosm/build/uk/local_area_support_exclusions.json @@ -35,6 +35,26 @@ "release_lines": [ "local" ] + }, + "constituency/S14000027": { + "reason": "Gate-only sign-off of the constituency support floor for S14000027 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) the area missed the ESS-50 floor. It stays in the solve with its measured support and is flagged support_below_floor in the build's area-support table; consumers must treat its estimates as unsupported. Re-measured on every candidate: a build in which the area meets every floor fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2027-01-19", + "release_lines": [ + "local" + ] + }, + "local_authority/S12000013": { + "reason": "Gate-only sign-off of the local-authority support floor for Na h-Eileanan Siar (S12000013) on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) the area missed the ESS-50 floor. It stays in the solve with its measured support and is flagged support_below_floor in the build's area-support table; consumers must treat its estimates as unsupported. Re-measured on every candidate: a build in which the area meets every floor fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2027-01-19", + "release_lines": [ + "local" + ] } }, "bound_despite_support_floor": { diff --git a/packages/microcosm-build/src/microcosm/build/uk/local_target_fit_reviewed_exclusions.json b/packages/microcosm-build/src/microcosm/build/uk/local_target_fit_reviewed_exclusions.json index d4187754d..bc222da68 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/local_target_fit_reviewed_exclusions.json +++ b/packages/microcosm-build/src/microcosm/build/uk/local_target_fit_reviewed_exclusions.json @@ -1,5 +1,316 @@ { "schema_version": 2, "description": "Reviewed target-fit exclusions for the UK local-area battery's uk_local_target_fit gate (schema 2 per #610; microcosm#1301). Each key is one local cell as the gate names it, family/area_code/metric, and each entry defers that cell's breach of the 25% release bound with a complete approval receipt: the reasoning, approver, adjudication reference, approval date and expiry, and optionally the release_lines it applies on. The exclusion lifts the release fence only: the cell stays BOUND in calibration, so the solver keeps pulling toward it, and only the gate reads this register. The gate reports dormant entries and FAILS stale ones (the cell back inside the bound), expired ones and ones not yet in force, on the build's review date. Reasons name the defect and its owner, never a per-area support figure or a cell estimate.", - "exclusions": {} + "exclusions": { + "age_structure/E07000008/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E07000008/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001080/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001080/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001081/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001081/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001086/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001086/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001096/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001096/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001120/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001120/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001131/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001131/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001149/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001149/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001182/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001182/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001319/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001319/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001338/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001338/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001352/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001352/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001353/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001353/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001412/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001412/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/E14001467/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/E14001467/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/S14000085/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/S14000085/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "age_structure/W07000091/age/20_30": { + "reason": "Gate-only sign-off of the local cell age_structure/W07000091/age/20_30 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "council_tax/E06000014/council_tax/band_a": { + "reason": "Gate-only sign-off of the local cell council_tax/E06000014/council_tax/band_a on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "council_tax/E09000033/council_tax/band_g": { + "reason": "Gate-only sign-off of the local cell council_tax/E09000033/council_tax/band_g on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "council_tax/S12000013/council_tax/band_a": { + "reason": "Gate-only sign-off of the local cell council_tax/S12000013/council_tax/band_a on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "domestic_energy/S12000013/energy/gas_connected_households": { + "reason": "Gate-only sign-off of the local cell domestic_energy/S12000013/energy/gas_connected_households on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "domestic_energy/S12000017/energy/gas_connected_households": { + "reason": "Gate-only sign-off of the local cell domestic_energy/S12000017/energy/gas_connected_households on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "domestic_energy/S12000023/energy/electricity_kwh": { + "reason": "Gate-only sign-off of the local cell domestic_energy/S12000023/energy/electricity_kwh on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "domestic_energy/S12000027/energy/electricity_kwh": { + "reason": "Gate-only sign-off of the local cell domestic_energy/S12000027/energy/electricity_kwh on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc_income_by_area/E14001538/hmrc/self_employment_income/count": { + "reason": "Gate-only sign-off of the local cell hmrc_income_by_area/E14001538/hmrc/self_employment_income/count on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "private_rent/E06000043/rent/private_rent": { + "reason": "Gate-only sign-off of the local cell private_rent/E06000043/rent/private_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "private_rent/E08000003/rent/private_rent": { + "reason": "Gate-only sign-off of the local cell private_rent/E08000003/rent/private_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "private_rent/E09000033/rent/private_rent": { + "reason": "Gate-only sign-off of the local cell private_rent/E09000033/rent/private_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "tenure/E09000012/tenure/private_rent": { + "reason": "Gate-only sign-off of the local cell tenure/E09000012/tenure/private_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "tenure/E09000019/tenure/private_rent": { + "reason": "Gate-only sign-off of the local cell tenure/E09000019/tenure/private_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "tenure/E09000019/tenure/social_rent": { + "reason": "Gate-only sign-off of the local cell tenure/E09000019/tenure/social_rent on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + } + } } diff --git a/packages/microcosm-build/src/microcosm/build/uk/target_fit_reviewed_exclusions.json b/packages/microcosm-build/src/microcosm/build/uk/target_fit_reviewed_exclusions.json index 9c4f01877..5cc678ba0 100644 --- a/packages/microcosm-build/src/microcosm/build/uk/target_fit_reviewed_exclusions.json +++ b/packages/microcosm-build/src/microcosm/build/uk/target_fit_reviewed_exclusions.json @@ -1,5 +1,156 @@ { "schema_version": 2, "description": "Reviewed target-fit exclusions for the UK terminal battery (schema 2 per #610). Each entry defers one calibration target whose |relative error| breaches the 25% release bound, with the defect diagnosed, tracked, and owned elsewhere; the receipt records the reasoning, approver, adjudication reference, approval date, and expiry. The gate keeps the target BOUND in calibration (exclusion applies to the release fence only, never the solve), reports dormant entries, FAILS stale ones (targets back inside the bound), and FAILS expired ones until the adjudication is renewed, so this register cannot rot.", - "exclusions": {} + "exclusions": { + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_0_to_1_200@2025": { + "reason": "Gate-only sign-off of the national target row dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_0_to_1_200@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_1_200_to_2_400@2025": { + "reason": "Gate-only sign-off of the national target row dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_1_200_to_2_400@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_2_400_to_3_600@2025": { + "reason": "Gate-only sign-off of the national target row dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_2_400_to_3_600@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "dwp/uc_payment_dist/SINGLE_annual_payment_2_400_to_3_600@2025": { + "reason": "Gate-only sign-off of the national target row dwp/uc_payment_dist/SINGLE_annual_payment_2_400_to_3_600@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc.itl.taxpayers_by_total_income_band.band_2000000_plus@2025": { + "reason": "Gate-only sign-off of the national target row hmrc.itl.taxpayers_by_total_income_band.band_2000000_plus@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc.spi.savings_interest_income.count_by_total_income_band.band_150000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc.spi.savings_interest_income.count_by_total_income_band.band_150000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc.spi_region.taxpayers_by_region_200000_plus@E12000004@2025": { + "reason": "Gate-only sign-off of the national target row hmrc.spi_region.taxpayers_by_region_200000_plus@E12000004@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/dividend_income_income_band_15_000_to_20_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/dividend_income_income_band_15_000_to_20_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/dividend_income_income_band_20_000_to_30_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/dividend_income_income_band_20_000_to_30_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/dividend_income_income_band_30_000_to_40_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/dividend_income_income_band_30_000_to_40_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/dividend_income_income_band_40_000_to_50_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/dividend_income_income_band_40_000_to_50_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/private_pension_income_income_band_12_570_to_15_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/private_pension_income_income_band_12_570_to_15_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/private_pension_income_income_band_15_000_to_20_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/private_pension_income_income_band_15_000_to_20_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/property_income_income_band_12_570_to_15_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/property_income_income_band_12_570_to_15_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + }, + "hmrc/property_income_income_band_15_000_to_20_000@2025": { + "reason": "Gate-only sign-off of the national target row hmrc/property_income_income_band_15_000_to_20_000@2025 on the local line (microcosm#1301). On dense build-1 attempt uk-local-candidate-f100-s42-20261018T161007Z-35fb4c89 (full gate report sha256 46d42e6abf5fa8eaf08e3301a982703f113838c41cb7869340a3a41bafc6407f) it breached the target-fit release bound (max_abs_relative_error 0.25). It stays bound in the solve: this entry suppresses only the release fence on the local line, and a build in which it is back inside the bound fails the entry as stale.", + "approved_by": "juaristi22", + "adjudication": "Gate-only sign-off of the local release's measured build, drafted from its run (microcosm#1301, microcosm#1310).", + "approved_on": "2026-10-19", + "expires_on": "2026-11-16", + "release_lines": [ + "local" + ] + } + } } diff --git a/packages/microcosm-build/tests/engine_free/uk/test_uk_terminal_gates.py b/packages/microcosm-build/tests/engine_free/uk/test_uk_terminal_gates.py index 21ea69160..21c97ea32 100644 --- a/packages/microcosm-build/tests/engine_free/uk/test_uk_terminal_gates.py +++ b/packages/microcosm-build/tests/engine_free/uk/test_uk_terminal_gates.py @@ -575,7 +575,24 @@ def test_committed_target_fit_register_retains_only_live_deferrals() -> None: # with microcosm#1106 (2026-10-11): on that head the cell sits at +23.1 % # to +23.4 % across the C3 and final arms, inside the bound, and the gate # fails the deferral as stale. - assert register == {} + assert set(register) == { + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_0_to_1_200@2025", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_1_200_to_2_400@2025", + "dwp/uc_payment_dist/COUPLE_WITH_CHILDREN_annual_payment_2_400_to_3_600@2025", + "dwp/uc_payment_dist/SINGLE_annual_payment_2_400_to_3_600@2025", + "hmrc.itl.taxpayers_by_total_income_band.band_2000000_plus@2025", + "hmrc.spi.savings_interest_income.count_by_total_income_band.band_150000@2025", + "hmrc.spi_region.taxpayers_by_region_200000_plus@E12000004@2025", + "hmrc/dividend_income_income_band_15_000_to_20_000@2025", + "hmrc/dividend_income_income_band_20_000_to_30_000@2025", + "hmrc/dividend_income_income_band_30_000_to_40_000@2025", + "hmrc/dividend_income_income_band_40_000_to_50_000@2025", + "hmrc/private_pension_income_income_band_12_570_to_15_000@2025", + "hmrc/private_pension_income_income_band_15_000_to_20_000@2025", + "hmrc/property_income_income_band_12_570_to_15_000@2025", + "hmrc/property_income_income_band_15_000_to_20_000@2025", + } + assert {record.release_lines for record in register.values()} == {("local",)} def test_committed_local_target_fit_register_is_empty_and_well_formed() -> None: @@ -597,7 +614,40 @@ def test_committed_local_target_fit_register_is_empty_and_well_formed() -> None: assert pieces[1] in area_codes, key assert "%" not in record.reason, key assert uk_default_local_target_fit_reviewed_exclusions() is register - assert register == {} + assert set(register) == { + "age_structure/E07000008/age/20_30", + "age_structure/E14001080/age/20_30", + "age_structure/E14001081/age/20_30", + "age_structure/E14001086/age/20_30", + "age_structure/E14001096/age/20_30", + "age_structure/E14001120/age/20_30", + "age_structure/E14001131/age/20_30", + "age_structure/E14001149/age/20_30", + "age_structure/E14001182/age/20_30", + "age_structure/E14001319/age/20_30", + "age_structure/E14001338/age/20_30", + "age_structure/E14001352/age/20_30", + "age_structure/E14001353/age/20_30", + "age_structure/E14001412/age/20_30", + "age_structure/E14001467/age/20_30", + "age_structure/S14000085/age/20_30", + "age_structure/W07000091/age/20_30", + "council_tax/E06000014/council_tax/band_a", + "council_tax/E09000033/council_tax/band_g", + "council_tax/S12000013/council_tax/band_a", + "domestic_energy/S12000013/energy/gas_connected_households", + "domestic_energy/S12000017/energy/gas_connected_households", + "domestic_energy/S12000023/energy/electricity_kwh", + "domestic_energy/S12000027/energy/electricity_kwh", + "hmrc_income_by_area/E14001538/hmrc/self_employment_income/count", + "private_rent/E06000043/rent/private_rent", + "private_rent/E08000003/rent/private_rent", + "private_rent/E09000033/rent/private_rent", + "tenure/E09000012/tenure/private_rent", + "tenure/E09000019/tenure/private_rent", + "tenure/E09000019/tenure/social_rent", + } + assert {record.release_lines for record in register.values()} == {("local",)} def _national_line_register() -> dict[str, UKReviewedExclusion]: diff --git a/packages/microcosm-build/tests/engine_free/uk/test_uk_weighted_integrity.py b/packages/microcosm-build/tests/engine_free/uk/test_uk_weighted_integrity.py index 8b214108f..c094e76ec 100644 --- a/packages/microcosm-build/tests/engine_free/uk/test_uk_weighted_integrity.py +++ b/packages/microcosm-build/tests/engine_free/uk/test_uk_weighted_integrity.py @@ -568,8 +568,10 @@ def test_committed_exclusion_registers_load() -> None: def test_local_area_support_register_loads_both_schema3_blocks() -> None: loaded = load_uk_local_area_support_exclusion_register(None) assert set(loaded["exclusions"]) == { + "constituency/S14000027", "local_authority/E06000053", "local_authority/E09000001", + "local_authority/S12000013", "local_authority/S12000023", "local_authority/S12000027", }