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/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/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/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/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/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/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/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/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/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-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( [ 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) 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). 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", } 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"