feat(modelling): explicit park-home guard in the solid-wall generator

ADR-0019 warns that wall_construction code 8 is Park home (PH), NOT system-
built. It was already excluded (8 isn't in the constructable-options map), but
only implicitly. Add an explicit early-return + named constant so a park home
can never be mis-keyed as system-built, with a pin as the tripwire. A park
home's proprietary panel is never EWI/IWI-suitable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-05 10:49:50 +00:00
parent 82cb30ee65
commit 36f74360a5
2 changed files with 25 additions and 0 deletions

View file

@ -40,6 +40,10 @@ _WALL_TIMBER_FRAME: Final[int] = 5
# disambiguated from basement by `main_wall_is_basement` below — a basement wall
# is never solid-wall-insulation-suitable regardless.
_WALL_SYSTEM_BUILT: Final[int] = 6
# Park home (`PH`, the Elmhurst code-8 wall) — NOT system-built (ADR-0019: "do
# not key system-built on 8"). A park home's wall is a proprietary panel system
# our EWI/IWI model doesn't represent, so it is never solid-wall-suitable.
_WALL_PARK_HOME: Final[int] = 8
# `wall_insulation_type`: 4 = as-built / assumed (uninsulated) — the trigger.
_WALL_AS_BUILT: Final[int] = 4
# `wall_insulation_type` the overlay lodges: 1 = external, 3 = internal.
@ -142,6 +146,8 @@ def recommend_solid_wall(
construction: object = main.wall_construction
if not isinstance(construction, int):
return None # a free-text site-notes construction is not a code we key on
if construction == _WALL_PARK_HOME:
return None # park home (code 8) — proprietary panel, never EWI/IWI
measure_types = _CONSTRUCTABLE_OPTIONS.get(construction)
if not measure_types:
return None

View file

@ -12,6 +12,7 @@ from domain.modelling.scoring.overlay_applicator import apply_simulations
from domain.modelling.product import Product
from domain.modelling.recommendation import Recommendation
from domain.modelling.generators.wall_recommendation import recommend_cavity_wall
from domain.modelling.generators.solid_wall_recommendation import recommend_solid_wall
from repositories.product.product_repository import ProductRepository
from tests.domain.sap10_calculator.worksheet._elmhurst_worksheet_000490 import (
build_epc,
@ -87,3 +88,21 @@ def test_non_cavity_main_wall_yields_no_recommendation() -> None:
# Assert
assert recommendation is None
def test_park_home_wall_yields_no_solid_wall_recommendation() -> None:
# Arrange — a park home (wall_construction code 8) with an uninsulated
# as-built wall. Code 8 is NOT system-built (ADR-0019); a park home's
# proprietary panel is never EWI/IWI-suitable, so the generator excludes it.
baseline: EpcPropertyData = build_epc()
main: SapBuildingPart = _part(baseline, BuildingPartIdentifier.MAIN)
main.wall_construction = 8
main.wall_insulation_type = 4 # as-built / uninsulated — the trigger
# Act
recommendation: Recommendation | None = recommend_solid_wall(
baseline, _StubProducts()
)
# Assert
assert recommendation is None