From f11fc9bc04425b6c2ecff7da89eaa0562e05b0f1 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 1 Jul 2026 11:06:50 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20a=20MIXED=20glazing=20override=20to?= =?UTF-8?q?=20no=20overlay,=20keeping=20the=20cert=20per-window=20glazing?= =?UTF-8?q?=20=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- tests/domain/epc/test_glazing_overlay.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/domain/epc/test_glazing_overlay.py b/tests/domain/epc/test_glazing_overlay.py index 3182d79cf..81c35e6ca 100644 --- a/tests/domain/epc/test_glazing_overlay.py +++ b/tests/domain/epc/test_glazing_overlay.py @@ -57,6 +57,18 @@ def test_unresolvable_glazing_produces_no_overlay(glazing_value: str) -> None: assert simulation is None +def test_a_glazing_mix_produces_no_overlay_so_the_cert_is_kept() -> None: + # A MIXED aggregate resolves to no overlay: a whole-dwelling proportion cannot + # say which windows are which, so the cert's per-window `sap_windows` are kept + # rather than flattened to one type (ADR-0042 amendment, #1376). + + # Act + simulation = glazing_overlay_for(GlazingType.MIXED.value, 0) + + # Assert + assert simulation is None + + def test_glazing_override_remaps_every_window_and_clears_lodged_u() -> None: # Arrange — baseline windows are double glazed (code 2, lodged U 2.8); the # landlord corrects the whole dwelling to single glazing. @@ -74,14 +86,18 @@ def test_glazing_override_remaps_every_window_and_clears_lodged_u() -> None: assert all(w.window_transmission_details is None for w in result.sap_windows) +_NO_OVERLAY_SENTINELS = {GlazingType.UNKNOWN, GlazingType.MIXED} + + @pytest.mark.parametrize( - "member", [m for m in GlazingType if m is not GlazingType.UNKNOWN] + "member", [m for m in GlazingType if m not in _NO_OVERLAY_SENTINELS] ) def test_every_resolvable_glazing_value_decodes_to_a_code( member: GlazingType, ) -> None: # A classifier emits a GlazingType value; if the overlay can't decode it the - # override silently no-ops. Every non-UNKNOWN member must resolve. + # override silently no-ops. Every member except the deliberate no-overlay + # sentinels (UNKNOWN, MIXED) must resolve to a code. # Act simulation = glazing_overlay_for(member.value, 0)