Add flat-roof insulation-thickness taxonomy members lock-step with the overlay 🟩

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-01 10:16:35 +00:00
parent 463d4df048
commit acf05584d6
2 changed files with 60 additions and 0 deletions

View file

@ -22,6 +22,28 @@ class RoofType(Enum):
FLAT_NO_INSULATION = "Flat, no insulation"
FLAT_NO_INSULATION_ASSUMED = "Flat, no insulation (assumed)"
# A flat roof with a known insulation depth. RdSAP 10 Table 16 col (1)
# ("joists at ceiling level and flat roof") scores flat roofs by thickness, so
# these carry the depth into the overlay (mirroring the PITCHED_LOFT_* ladder;
# no "loft" — a flat roof has none). ADR-0041. The value column is an FE-owned
# pgEnum, so these members are added to the Drizzle enum by the FE owner.
FLAT_12MM = "Flat, 12 mm insulation"
FLAT_25MM = "Flat, 25 mm insulation"
FLAT_50MM = "Flat, 50 mm insulation"
FLAT_75MM = "Flat, 75 mm insulation"
FLAT_100MM = "Flat, 100 mm insulation"
FLAT_125MM = "Flat, 125 mm insulation"
FLAT_150MM = "Flat, 150 mm insulation"
FLAT_175MM = "Flat, 175 mm insulation"
FLAT_200MM = "Flat, 200 mm insulation"
FLAT_225MM = "Flat, 225 mm insulation"
FLAT_250MM = "Flat, 250 mm insulation"
FLAT_270MM = "Flat, 270 mm insulation"
FLAT_300MM = "Flat, 300 mm insulation"
FLAT_350MM = "Flat, 350 mm insulation"
FLAT_400MM = "Flat, 400 mm insulation"
FLAT_400_PLUS = "Flat, 400+ mm insulation"
PITCHED_INSULATED = "Pitched, insulated"
PITCHED_INSULATED_ASSUMED = "Pitched, insulated (assumed)"
PITCHED_INSULATED_AT_RAFTERS = "Pitched, insulated at rafters"

View file

@ -11,6 +11,26 @@ import pytest
from datatypes.epc.domain.epc_property_data import BuildingPartIdentifier
from domain.epc.property_overlays.roof_type_overlay import roof_overlay_for
from domain.epc.property_overrides.roof_type import RoofType
_FLAT_THICKNESS_MEMBERS: list[tuple[RoofType, int]] = [
(RoofType.FLAT_12MM, 12),
(RoofType.FLAT_25MM, 25),
(RoofType.FLAT_50MM, 50),
(RoofType.FLAT_75MM, 75),
(RoofType.FLAT_100MM, 100),
(RoofType.FLAT_125MM, 125),
(RoofType.FLAT_150MM, 150),
(RoofType.FLAT_175MM, 175),
(RoofType.FLAT_200MM, 200),
(RoofType.FLAT_225MM, 225),
(RoofType.FLAT_250MM, 250),
(RoofType.FLAT_270MM, 270),
(RoofType.FLAT_300MM, 300),
(RoofType.FLAT_350MM, 350),
(RoofType.FLAT_400MM, 400),
(RoofType.FLAT_400_PLUS, 400),
]
def test_pitched_loft_depth_maps_to_roof_insulation_thickness() -> None:
@ -56,6 +76,24 @@ def test_flat_roof_depth_maps_to_roof_insulation_thickness() -> None:
assert overlay.roof_insulation_thickness == 150
@pytest.mark.parametrize(("member", "expected_mm"), _FLAT_THICKNESS_MEMBERS)
def test_every_flat_thickness_member_resolves_to_its_depth(
member: RoofType, expected_mm: int
) -> None:
# Each FLAT_*MM taxonomy member must stay lock-step with the overlay: its value
# resolves to the depth it names (so a landlord-stored member scores via Table
# 16 col (1), not the age-band default). ADR-0041.
# Act
simulation = roof_overlay_for(member.value, 0)
# Assert
assert simulation is not None
overlay = simulation.building_parts[BuildingPartIdentifier.MAIN]
assert overlay.roof_construction_type == "Flat"
assert overlay.roof_insulation_thickness == expected_mm
@pytest.mark.parametrize(
"roof_type_value",
[