Stop a System-built landlord override being mis-read as a basement 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-29 19:30:25 +00:00
parent 6ec0989283
commit da17ddce8f
2 changed files with 32 additions and 0 deletions

View file

@ -36,6 +36,14 @@ class BuildingPartOverlay:
construction_age_band: Optional[str] = None
wall_construction: Optional[int] = None
wall_insulation_type: Optional[int] = None
# Disambiguates the RdSAP `wall_construction == 6` code collision: gov-EPC
# code 6 = "Basement wall" but RdSAP `WALL_SYSTEM_BUILT` is also 6, and
# `SapBuildingPart.main_wall_is_basement` falls back to the code-6 heuristic
# when the flag is `None`. A Landlord Override that sets a System-built wall
# (construction 6) must therefore set this `False` so the override isn't
# mis-read as a basement — the overlay-path mirror of the gov-API mapper's
# `_clear_basement_flag_when_system_built`.
wall_is_basement: Optional[bool] = None
# Added solid-wall insulation depth (mm) — drives the calculator's Table 6
# bucket / §5.8 documentary U-value for EWI (`wall_insulation_type=1`) and
# IWI (`wall_insulation_type=3`); λ defaults to 0.04 W/m·K in the calculator.

View file

@ -25,6 +25,30 @@ def test_solid_brick_with_internal_insulation_overlays_main_wall() -> None:
assert overlay.wall_insulation_type == 3
def test_system_built_override_is_not_mis_read_as_a_basement() -> None:
# A System-built wall is RdSAP code 6, which collides with the gov-EPC
# code-6 basement sentinel. The overlay must set wall_is_basement=False so
# main_wall_is_basement doesn't fire the code-6 heuristic (phantom basement).
simulation = wall_overlay_for(
"System built, as built, no insulation (assumed)", 0
)
assert simulation is not None
overlay = simulation.building_parts[BuildingPartIdentifier.MAIN]
assert overlay.wall_construction == 6
assert overlay.wall_is_basement is False
def test_non_system_built_override_leaves_basement_flag_untouched() -> None:
# Cavity (code 4) can't collide with the basement sentinel, so the overlay
# must not assert a basement verdict either way — leave the flag None.
simulation = wall_overlay_for("Cavity wall, with internal insulation", 0)
assert simulation is not None
overlay = simulation.building_parts[BuildingPartIdentifier.MAIN]
assert overlay.wall_is_basement is None
@pytest.mark.parametrize(
("wall_type_value", "construction", "insulation"),
[