diff --git a/tests/domain/modelling/test_roof_recommendation.py b/tests/domain/modelling/test_roof_recommendation.py index 77e9c0124..6759341ed 100644 --- a/tests/domain/modelling/test_roof_recommendation.py +++ b/tests/domain/modelling/test_roof_recommendation.py @@ -170,9 +170,12 @@ def test_vaulted_ceiling_with_measured_thickness_yields_no_recommendation() -> N def test_loft_roof_with_nd_thickness_on_pre_1950_dwelling_yields_loft_insulation() -> None: # Arrange — the loft fallback shares the sentinel semantics (ADR-0047): # "ND" on an age-band-C pitched loft resolves to as-built uninsulated, so - # the joist measure fires just as it does for an explicit 0. + # the joist measure fires just as it does for an explicit 0. The lodged + # type is the gov-API code-4 string — sentinel resolution needs a KNOWN + # pitched roof (an unlodged type could be a party ceiling; see below). baseline: EpcPropertyData = build_epc() main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) + main.roof_construction_type = "Pitched (slates/tiles), access to loft" main.roof_insulation_thickness = "ND" main.construction_age_band = "C" @@ -191,6 +194,28 @@ def test_loft_roof_with_nd_thickness_on_pre_1950_dwelling_yields_loft_insulation ) +def test_unlodged_roof_type_with_nd_thickness_yields_no_recommendation() -> None: + # Arrange — a part with NO lodged roof type reaching the loft fallback can + # be a party ceiling ("(another dwelling above)", gov-API codes 6/7 map the + # type to None and real code-7 certs lodge "ND"): zero roof heat loss, so + # insulating it contradicts the dwelling. Sentinel resolution therefore + # requires a KNOWN pitched/thatched roof; an unlodged type keeps the + # explicit-0-only trigger (ADR-0047). + baseline: EpcPropertyData = build_epc() + main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN) + main.roof_construction_type = None + main.roof_insulation_thickness = "ND" + main.construction_age_band = "B" + + # Act + recommendation: Recommendation | None = recommend_roof_insulation( + baseline, _StubProducts() + ) + + # Assert + assert recommendation is None + + def test_loft_option_carries_cost_from_roof_area_and_product() -> None: # Arrange baseline: EpcPropertyData = build_epc() # MAIN roof area 14.85 m^2