Classify an aggregate-mix glazing description as MIXED 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-01 11:03:28 +00:00
parent 19c1a78613
commit f959cc14c9
3 changed files with 47 additions and 0 deletions

View file

@ -0,0 +1,24 @@
from __future__ import annotations
from typing import Optional
from domain.epc.property_overrides.glazing_type import GlazingType
def glazing_mix_guard(description: str) -> Optional[GlazingType]:
"""Deterministically resolve an aggregate-mix glazing description to ``MIXED``.
A landlord glazing description is often a whole-dwelling proportion split
("40% double glazing 2002 or later, 60% single glazing"). Such a mix cannot be
faithfully applied per-window it says *how much* is each type, not *which*
windows and the cert already carries the true per-window glazing, so a mix
must resolve to ``GlazingType.MIXED`` (no overlay the cert is kept), never to
a single dominant type that would flatten every window (ADR-0042).
Recognises the structured ``"N% <type>, M% <type>"`` split and returns
``MIXED`` when it is a genuine mix two or more glazing types present and none
dominant ( the uniform threshold). Returns ``None`` for a uniform / near-
uniform assertion or an unparseable description, so the LLM classifier still
resolves it (a uniform reglaze is applied; varied phrasings are the LLM's job).
"""
raise NotImplementedError

View file

@ -21,4 +21,11 @@ class GlazingType(Enum):
DOUBLE_PRE_2002 = "Double glazing, pre-2002"
TRIPLE_PRE_2002 = "Triple glazing, pre-2002"
TRIPLE_POST_2002 = "Triple glazing, 2002 or later"
# An aggregate mix of glazing types across the dwelling ("40% double, 60%
# single"). Deliberately absent from the overlay's `_GLAZING_CODES`, so it
# resolves to no overlay and the cert's per-window `sap_windows` are kept
# rather than flattened to one type — a whole-dwelling proportion cannot say
# which windows are which (ADR-0042 amendment, #1376). The FE-owned pgEnum
# gains this member via a Drizzle migration.
MIXED = "Mixed glazing"
UNKNOWN = "Unknown"

View file

@ -0,0 +1,16 @@
from __future__ import annotations
from domain.epc.property_overrides.glazing_type import GlazingType
from domain.epc.property_overrides.glazing_mix_guard import glazing_mix_guard
def test_a_genuine_percentage_mix_classifies_as_mixed() -> None:
# Arrange — the bug: an aggregate mix the LLM would flatten to "Double".
description = "40% double glazing 2002 or later, 60% single glazing"
# Act
result = glazing_mix_guard(description)
# Assert — a mix defers to the cert's per-window glazing, not a whole-dwelling
# type.
assert result is GlazingType.MIXED