From 870cb04631db543cae880543d770f2fcfd78a41b Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 23 Jul 2026 13:47:11 +0000 Subject: [PATCH] =?UTF-8?q?Resolve=20a=20depthless=20sloping-ceiling=20mar?= =?UTF-8?q?ker=20to=20as=20built=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) --- .../roof_sloping_ceiling_guard.py | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/domain/epc/property_overrides/roof_sloping_ceiling_guard.py b/domain/epc/property_overrides/roof_sloping_ceiling_guard.py index 22ade4d28..e9de671cf 100644 --- a/domain/epc/property_overrides/roof_sloping_ceiling_guard.py +++ b/domain/epc/property_overrides/roof_sloping_ceiling_guard.py @@ -1,9 +1,29 @@ from __future__ import annotations +import re from typing import Optional from domain.epc.property_overrides.roof_type import RoofType +# The gov-API sloping-ceiling roof token (before any ``: `` suffix), +# normalised to lower alphanumerics. A slope-following ceiling (roof_construction +# 8) has no loft void, so it must resolve to the `Pitched, sloping ceiling, …` +# family, never the loft ladder (ADR-0066). +_SLOPING_CEILING_TOKEN = "pitchedwithslopingceiling" + + +def _normalise_roof_token(description: str) -> str: + token = description.split(":", 1)[0] + return re.sub(r"[^a-z0-9]", "", token.lower()) + def roof_sloping_ceiling_guard(description: str) -> Optional[RoofType]: - raise NotImplementedError + """Deterministically resolve a `PitchedWithSlopingCeiling` roof description to + its `Pitched, sloping ceiling, …` RoofType member (ADR-0066). + + Returns None for anything that is not a sloping-ceiling marker, so the + party-ceiling guard and the LLM classifier still handle the rest. + """ + if _normalise_roof_token(description) != _SLOPING_CEILING_TOKEN: + return None + return RoofType.PITCHED_SLOPING_CEILING_AS_BUILT