mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-08-03 05:18:22 +00:00
106 lines
3.9 KiB
Python
106 lines
3.9 KiB
Python
"""The pitched-sloping-ceiling roof guard (ADR-0066).
|
|
|
|
`PitchedWithSlopingCeiling: <As Built | Unknown | N mm>` 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
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
("description", "expected"),
|
|
[
|
|
# Exact tabulated depths → their own member.
|
|
("PitchedWithSlopingCeiling: 12mm", RoofType.PITCHED_SLOPING_CEILING_12MM),
|
|
("PitchedWithSlopingCeiling: 100mm", RoofType.PITCHED_SLOPING_CEILING_100MM),
|
|
("PitchedWithSlopingCeiling: 150 mm", RoofType.PITCHED_SLOPING_CEILING_150MM),
|
|
("PitchedWithSlopingCeiling: 270mm", RoofType.PITCHED_SLOPING_CEILING_270MM),
|
|
("PitchedWithSlopingCeiling: 400mm", RoofType.PITCHED_SLOPING_CEILING_400MM),
|
|
# Off-ladder depth snaps to the nearest tabulated depth ≤ N (mirrors the
|
|
# calculator's `_ROOF_BY_THICKNESS` picker), so nothing leaks to the LLM.
|
|
("PitchedWithSlopingCeiling: 130mm", RoofType.PITCHED_SLOPING_CEILING_125MM),
|
|
# Above 400 mm, or an explicit "400+" lodgement → the 400+ member.
|
|
("PitchedWithSlopingCeiling: 450mm", RoofType.PITCHED_SLOPING_CEILING_400_PLUS),
|
|
("PitchedWithSlopingCeiling: 400+mm", RoofType.PITCHED_SLOPING_CEILING_400_PLUS),
|
|
],
|
|
)
|
|
def test_sloping_ceiling_measured_depth_resolves_to_its_ladder_member(
|
|
description: str, expected: RoofType
|
|
) -> None:
|
|
# ADR-0066: a measured sloping-ceiling depth rides onto the matching ladder
|
|
# member (Table 17 col (1a)); off-ladder depths snap down; ≥ 400 / "400+"
|
|
# caps at the top member.
|
|
|
|
# Act
|
|
member = roof_sloping_ceiling_guard(description)
|
|
|
|
# Assert
|
|
assert member is expected
|
|
|
|
|
|
def test_sloping_ceiling_depth_below_the_ladder_falls_back_to_as_built() -> None:
|
|
# No member exists below 12 mm; a sub-ladder depth defers to `as built` (the
|
|
# age band drives it — uninsulated at old bands anyway), never inventing a
|
|
# member or leaking to the loft LLM route.
|
|
|
|
# Act
|
|
member = roof_sloping_ceiling_guard("PitchedWithSlopingCeiling: 5mm")
|
|
|
|
# Assert
|
|
assert member is RoofType.PITCHED_SLOPING_CEILING_AS_BUILT
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"description",
|
|
[
|
|
"Pitched, 150 mm loft insulation",
|
|
"PitchedNormalLoftAccess: 150mm",
|
|
"anotherdwellingabove: 100mm",
|
|
"Flat: As Built",
|
|
"",
|
|
],
|
|
)
|
|
def test_non_sloping_ceiling_descriptions_are_not_guarded(description: str) -> None:
|
|
# A description that is not a sloping-ceiling marker returns None, so the
|
|
# party-ceiling guard and the LLM classifier still handle it (#1376 pattern).
|
|
|
|
# Act
|
|
member = roof_sloping_ceiling_guard(description)
|
|
|
|
# Assert
|
|
assert member is None
|