From 82ac8c341b04f81110ed25c8e3caf4c491e936b8 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Jul 2026 13:50:13 +0000 Subject: [PATCH] =?UTF-8?q?Compose=20the=20party-ceiling=20and=20sloping-c?= =?UTF-8?q?eiling=20roof=20guards=20ahead=20of=20the=20LLM=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) --- domain/epc/property_overrides/roof_guard.py | 9 +++++ tests/domain/epc/test_roof_guard.py | 37 +++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 domain/epc/property_overrides/roof_guard.py create mode 100644 tests/domain/epc/test_roof_guard.py diff --git a/domain/epc/property_overrides/roof_guard.py b/domain/epc/property_overrides/roof_guard.py new file mode 100644 index 000000000..e3203e950 --- /dev/null +++ b/domain/epc/property_overrides/roof_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_guard(description: str) -> Optional[RoofType]: + raise NotImplementedError diff --git a/tests/domain/epc/test_roof_guard.py b/tests/domain/epc/test_roof_guard.py new file mode 100644 index 000000000..afb86923b --- /dev/null +++ b/tests/domain/epc/test_roof_guard.py @@ -0,0 +1,37 @@ +"""The composed roof guard wired into the roof `GuardedColumnClassifier`. + +Two deterministic roof guards compose ahead of the LLM fallback: the +party-ceiling guard (#1376) and the sloping-ceiling guard (ADR-0066). A roof +description that neither recognises returns None and reaches the LLM. +""" + +from __future__ import annotations + +from domain.epc.property_overrides.roof_guard import roof_guard +from domain.epc.property_overrides.roof_type import RoofType + + +def test_party_ceiling_marker_resolves_to_its_party_member() -> None: + # Act + member = roof_guard("another dwelling above") + + # Assert + assert member is RoofType.ADJACENT_ANOTHER_DWELLING_ABOVE + + +def test_sloping_ceiling_marker_resolves_to_the_sloping_family() -> None: + # Act + member = roof_guard("PitchedWithSlopingCeiling: 150mm") + + # Assert + assert member is RoofType.PITCHED_SLOPING_CEILING_150MM + + +def test_a_plain_loft_description_is_left_for_the_llm() -> None: + # Neither deterministic guard recognises a loft depth, so it reaches the LLM. + + # Act + member = roof_guard("Pitched, 150 mm loft insulation") + + # Assert + assert member is None