Resolve the cohort's remaining PasHub boiler control labels to Table 4e codes 🟥

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-14 16:20:38 +00:00
parent 59215c822e
commit a213150d7d

View file

@ -866,3 +866,63 @@ class TestPasHubUnmappedMainFuel:
# Assert
assert result.sap_heating.main_heating_details[0].main_fuel_type == 30
class TestPasHubMainHeatingControlCoding:
"""Each main-heating Controls label the Guinness cohort lodges resolves to
its SAP 10.2 Table 4e Group 1 (PDF p.171) boiler-control code. The mapper
emits the int code (not the raw label) so the calculator's `_control_type`
keys off it instead of strict-raising `UnmappedSapCode` deep in the cascade.
The resulting control type is the spec's, not a blanket "type 2": a
programmer + a single room thermostat (2104) is type 1; type 2 needs more
(2+ room thermostats, or TRVs).
"""
# (label, Table 4e code, Table 9 control type) — codes/types straight from
# SAP 10.2 Table 4e Group 1.
_LABEL_CODE_TYPE = [
("Programmer and room thermostat", 2104, 1),
("Programmer, TRVs and bypass", 2107, 2),
("Room thermostat and TRVs", 2113, 2),
("TRVs and bypass", 2111, 2),
]
@pytest.mark.parametrize(
"label, code", [(lbl, code) for lbl, code, _ in _LABEL_CODE_TYPE]
)
def test_control_label_maps_to_sap_code(self, label: str, code: int) -> None:
# Arrange — the example fixture with its Controls cell overridden.
raw = load("pashub_rdsap_site_notes_example1.json")
raw["heating_and_hot_water"]["main_heating"]["controls"] = label
survey = from_dict(PasHubRdSapSiteNotes, raw)
# Act
result = EpcPropertyDataMapper.from_site_notes(survey)
# Assert
assert (
result.sap_heating.main_heating_details[0].main_heating_control == code
)
@pytest.mark.parametrize(
"label, control_type", [(lbl, ct) for lbl, _, ct in _LABEL_CODE_TYPE]
)
def test_mapped_control_yields_spec_control_type(
self, label: str, control_type: int
) -> None:
# Arrange — drive the mapped code through the calculator's control-type
# classifier to pin the end-to-end control type per Table 4e.
from domain.sap10_calculator.rdsap.cert_to_inputs import ( # pyright: ignore[reportPrivateUsage]
_control_type,
)
raw = load("pashub_rdsap_site_notes_example1.json")
raw["heating_and_hot_water"]["main_heating"]["controls"] = label
survey = from_dict(PasHubRdSapSiteNotes, raw)
main = EpcPropertyDataMapper.from_site_notes(
survey
).sap_heating.main_heating_details[0]
# Act / Assert
assert _control_type(main) == control_type