Gate the loft top-up strictly below the 270mm building-regs depth 🟩

Locks the gate edges — a lodged pitched loft below 270mm is recommended, a
loft at 270mm is left alone, and the 'Nmm+' form ('300mm+') parses to its
number and stays ineligible. These passed on arrival (they fell out of the
numeric-parse gate added in the previous commit); pinned as regression guards.
ADR-0063.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-10 16:07:48 +00:00
parent 95a0da4828
commit 3bbe293f68

View file

@ -242,6 +242,55 @@ def test_loft_below_building_regs_depth_yields_loft_insulation() -> None:
)
def test_lodged_pitched_loft_below_regs_yields_loft_insulation() -> None:
# Arrange — the below-regs gate also fires on a KNOWN pitched loft with a
# partial lodged depth (150 mm), not only the unlodged shape: the numeric
# rule applies regardless of roof type (ADR-0063).
baseline: EpcPropertyData = build_epc()
main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN)
main.roof_construction_type = "Pitched (slates/tiles), access to loft"
main.roof_insulation_thickness = "150mm"
# Act
recommendation: Recommendation | None = recommend_roof_insulation(
baseline, _StubProducts()
)
# Assert
assert recommendation is not None
assert recommendation.options[0].measure_type == "loft_insulation"
def test_loft_at_the_building_regs_depth_yields_no_recommendation() -> None:
# Arrange — 270 mm is the compliance gate: a loft AT the standard is not
# sub-standard, so it is left alone (strict below-270, ADR-0063).
baseline: EpcPropertyData = build_epc()
_part(baseline, BuildingPartIdentifier.MAIN).roof_insulation_thickness = "270mm"
# Act
recommendation: Recommendation | None = recommend_roof_insulation(
baseline, _StubProducts()
)
# Assert
assert recommendation is None
def test_loft_with_a_plus_suffix_depth_above_regs_yields_no_recommendation() -> None:
# Arrange — the "Nmm+" lodged form ("300mm+") parses to its number (300),
# which is at/above the gate, so no top-up is offered (ADR-0063).
baseline: EpcPropertyData = build_epc()
_part(baseline, BuildingPartIdentifier.MAIN).roof_insulation_thickness = "300mm+"
# Act
recommendation: Recommendation | None = recommend_roof_insulation(
baseline, _StubProducts()
)
# Assert
assert recommendation is None
def test_loft_option_carries_cost_from_roof_area_and_product() -> None:
# Arrange
baseline: EpcPropertyData = build_epc() # MAIN roof area 14.85 m^2