From 6603d98c2c4ff2651fea246183a484354ca9b722 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Jul 2026 13:46:49 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20a=20depthless=20sloping-ceiling=20mar?= =?UTF-8?q?ker=20to=20as=20built=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) --- .../roof_sloping_ceiling_guard.py | 9 ++++ .../epc/test_roof_sloping_ceiling_guard.py | 42 +++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 domain/epc/property_overrides/roof_sloping_ceiling_guard.py create mode 100644 tests/domain/epc/test_roof_sloping_ceiling_guard.py diff --git a/domain/epc/property_overrides/roof_sloping_ceiling_guard.py b/domain/epc/property_overrides/roof_sloping_ceiling_guard.py new file mode 100644 index 000000000..22ade4d28 --- /dev/null +++ b/domain/epc/property_overrides/roof_sloping_ceiling_guard.py @@ -0,0 +1,9 @@ +from __future__ import annotations + +from typing import Optional + +from domain.epc.property_overrides.roof_type import RoofType + + +def roof_sloping_ceiling_guard(description: str) -> Optional[RoofType]: + raise NotImplementedError diff --git a/tests/domain/epc/test_roof_sloping_ceiling_guard.py b/tests/domain/epc/test_roof_sloping_ceiling_guard.py new file mode 100644 index 000000000..022b36460 --- /dev/null +++ b/tests/domain/epc/test_roof_sloping_ceiling_guard.py @@ -0,0 +1,42 @@ +"""The pitched-sloping-ceiling roof guard (ADR-0066). + +`PitchedWithSlopingCeiling: ` is a slope-following +ceiling (gov-API roof_construction 8), NOT a horizontal loft — so it must +resolve deterministically to the `Pitched, sloping ceiling, …` family and never +reach the LLM to be routed onto the `Pitched, N mm loft insulation` ladder. Same +defect class the party-ceiling guard was created for (#1376): the LLM resolves +identical inputs inconsistently, and the near-duplicate loft members are exactly +the ambiguity. Returns None for anything that is not a sloping-ceiling marker so +the LLM (and the party-ceiling guard) still handle the rest. +""" + +from __future__ import annotations + +import pytest + +from domain.epc.property_overrides.roof_sloping_ceiling_guard import ( + roof_sloping_ceiling_guard, +) +from domain.epc.property_overrides.roof_type import RoofType + + +@pytest.mark.parametrize( + "description", + [ + "PitchedWithSlopingCeiling: As Built", + "PitchedWithSlopingCeiling: Unknown", + "PitchedWithSlopingCeiling", + "PitchedWithSlopingCeiling: ", + ], +) +def test_sloping_ceiling_without_a_depth_resolves_to_as_built( + description: str, +) -> None: + # ADR-0066: a sloping ceiling with no measured depth ("As Built" / "Unknown" + # / nothing) folds to `as built`, which defers the U-value to the age band. + + # Act + member = roof_sloping_ceiling_guard(description) + + # Assert + assert member is RoofType.PITCHED_SLOPING_CEILING_AS_BUILT