From 0d465346c9a478516f2e50d1989ebd917a0526d7 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 2 Jul 2026 10:55:58 +0000 Subject: [PATCH] =?UTF-8?q?Vaulted=20ND=20roof=20on=20a=20pre-1950=20dwell?= =?UTF-8?q?ing=20gets=20sloping-ceiling=20insulation=20=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- .../modelling/test_roof_recommendation.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/domain/modelling/test_roof_recommendation.py b/tests/domain/modelling/test_roof_recommendation.py index 63f28ce68..9e36b25f8 100644 --- a/tests/domain/modelling/test_roof_recommendation.py +++ b/tests/domain/modelling/test_roof_recommendation.py @@ -83,6 +83,34 @@ def test_room_in_roof_yields_no_recommendation_pending_a_dedicated_branch() -> N assert recommendation is None +def test_vaulted_ceiling_with_nd_thickness_on_pre_1950_dwelling_yields_sloping_ceiling_insulation() -> None: + # Arrange — the 742265 shape (ADR-0047): a "Pitched (vaulted ceiling)" MAIN + # roof lodging the "ND" sentinel on an age-band-B dwelling. ND resolves to + # the age band's as-built state (A-D: uninsulated), and a vaulted ceiling + # has no loft void, so the one applicable Measure is rafter insulation. + baseline: EpcPropertyData = build_epc() + main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) + main.roof_construction_type = "Pitched (vaulted ceiling)" + main.roof_insulation_thickness = "ND" + main.construction_age_band = "B" + + # Act + recommendation: Recommendation | None = recommend_roof_insulation( + baseline, _StubProducts() + ) + + # Assert + assert recommendation is not None + assert recommendation.surface == "Roof" + assert len(recommendation.options) == 1 + option = recommendation.options[0] + assert option.measure_type == "sloping_ceiling_insulation" + simulated: EpcPropertyData = apply_simulations(baseline, [option.overlay]) + assert ( + _part(simulated, BuildingPartIdentifier.MAIN).roof_insulation_thickness == 100 + ) + + def test_loft_option_carries_cost_from_roof_area_and_product() -> None: # Arrange baseline: EpcPropertyData = build_epc() # MAIN roof area 14.85 m^2