Model/tests/domain/epc_prediction/test_historic_conditioning.py
Khalim Conn-Kowlessar 49c9f8181c The historic roof description conditions the cohort by form family 🟥
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 11:50:45 +00:00

117 lines
4.7 KiB
Python

"""HistoricConditioning resolves an expired Historic EPC's stable attributes
into the cohort's code spaces (ADR-0054).
Only stable attributes are resolved — volatile ones (heating system, glazing,
PV, insulation states) never condition prediction. Every resolver degrades to
None on an unresolvable value, which leaves its cohort filter inactive.
"""
from __future__ import annotations
import dataclasses
from datatypes.epc.domain.historic_epc import HistoricEpc
from domain.epc_prediction.historic_conditioning import (
HistoricConditioning,
conditioning_from_historic,
)
def _hist(**overrides: str) -> HistoricEpc:
fields = {f.name: "" for f in dataclasses.fields(HistoricEpc)}
fields.update(overrides)
return HistoricEpc(**fields)
def test_resolves_stable_attributes_into_cohort_code_spaces():
# Arrange — display-text values exactly as the old register lodged them.
record = _hist(
property_type="House",
built_form="Semi-Detached",
walls_description="Cavity wall, as built, no insulation (assumed)",
roof_description="Pitched, 100 mm loft insulation",
construction_age_band="England and Wales: 1930-1949",
main_fuel="mains gas (not community)",
total_floor_area="84",
)
# Act
conditioning = conditioning_from_historic(record)
# Assert — each attribute lands in the code space its cohort filter compares.
assert isinstance(conditioning, HistoricConditioning)
assert conditioning.property_type == "0"
assert conditioning.built_form == "2"
assert conditioning.wall_construction == 4
assert conditioning.roof_form == "pitched"
assert conditioning.construction_age_band == "C"
assert conditioning.main_fuel == 26
assert conditioning.total_floor_area_m2 == 84.0
def test_roof_descriptions_resolve_to_form_families():
# Arrange / Act / Assert — the FORM half of the description (before the
# comma) maps to a family, because the API's roof_construction codes group
# that way (7,974-cert co-occurrence sweep: 1=Flat 98%, 4/5/8=Pitched
# 88-99%, 3=another dwelling above 100%; 7/9=another premises above per
# the #1452 suppression fix). Insulation state is volatile and ignored.
cases = {
"Pitched, 250 mm loft insulation": "pitched",
"Pitched, no insulation (assumed)": "pitched",
"Flat, insulated (assumed)": "flat",
"(another dwelling above)": "dwelling_above",
"(another premises above)": "premises_above",
}
for text, family in cases.items():
record = _hist(roof_description=text)
assert conditioning_from_historic(record).roof_form == family, text
# Unpinned forms (roof rooms, thatched) must not guess.
assert conditioning_from_historic(
_hist(roof_description="Roof room(s), insulated")
).roof_form is None
assert conditioning_from_historic(
_hist(roof_description="Thatched, with additional insulation")
).roof_form is None
def test_legacy_register_fuel_descriptions_resolve():
# Arrange / Act / Assert — the old register lodged pre-RdSAP-17 fuels with
# a "backwards compatibility" rider or a SAP-style prefix; they name the
# same physical fuels (dominant in the pre-2012 dump: a 65-shard scan found
# 636/663 unresolved values were these variants).
cases = {
"mains gas - this is for backwards compatibility only and should not be used": 26,
"electricity - this is for backwards compatibility only and should not be used": 29,
"LPG - this is for backwards compatibility only and should not be used": 27,
"oil - this is for backwards compatibility only and should not be used": 28,
"Gas: mains gas": 26,
"Electricity: electricity, unspecified tariff": 29,
"dual fuel - mineral + wood": 10,
}
for text, code in cases.items():
record = _hist(main_fuel=text)
assert conditioning_from_historic(record).main_fuel == code, text
def test_unresolvable_values_degrade_to_none():
# Arrange — junk and blanks must never guess a code.
record = _hist(
property_type="Castle",
built_form="Not Recorded",
walls_description="Average thermal transmittance 0.3 W/m²K",
construction_age_band="INVALID!",
main_fuel="To be used only when there is no heating system",
total_floor_area="",
)
# Act
conditioning = conditioning_from_historic(record)
# Assert
assert conditioning.property_type is None
assert conditioning.built_form is None
assert conditioning.wall_construction is None
assert conditioning.roof_form is None
assert conditioning.construction_age_band is None
assert conditioning.main_fuel is None
assert conditioning.total_floor_area_m2 is None