Rate MVHR dwellings via Table 4g and biomass heat networks via Table 12 code 43 🟩

#1637: 'MV - Heat Recovery' → MVHR kind (Table 4g default 46.2% heat
recovery — PasHub lodges no PCDF product/wet-rooms/duct data, so these
land in the accuracy tail as the issue predicts). Unblocking them
surfaced 4 biomass heat networks whose fuel label 'Heat from boilers -
biomass' passed through raw to the calculator's MissingMainFuelType —
now mapped to Table 12 code 43, and any other uncovered community fuel
strict-raises UnmappedPasHubLabel at the boundary (ADR-0015).
LRHA 61→76 computed / 28 blocked / 0 errored, within-0.5 43.4%,
MAE 2.985 — ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-16 16:04:05 +00:00
parent 38e9ebd5c7
commit 6750e48609

View file

@ -6551,6 +6551,13 @@ _PASHUB_VENTILATION_TYPE_TO_KIND: Dict[str, Optional[str]] = {
"Mechanical Extract - Centralised": "EXTRACT_OR_PIV_OUTSIDE",
"Positive Input - From Outside": "EXTRACT_OR_PIV_OUTSIDE",
"Positive Input - From Loft (As Natural)": None,
# Balanced mechanical ventilation with heat recovery. PasHub's survey
# form carries no PCDF product index / wet-room count / duct type, so
# `_mvhr_system_values` always takes the Table 4g default branch
# (66% × 0.70 in-use = 46.2% heat recovery) regardless of the installed
# unit — expect these dwellings in the accuracy tail until PasHub
# captures the MVHR product reference (#1637).
"MV - Heat Recovery": "MVHR",
}
@ -6581,6 +6588,14 @@ _PASHUB_COMMUNITY_HEAT_SOURCE_TO_ELMHURST: Dict[str, str] = {
"Community heating - boilers only": "Boilers",
}
# PasHub community-fuel labels that use SAP 10.2 Table 12 row wording rather
# than the Elmhurst §14.1 vocabulary (`_ELMHURST_COMMUNITY_BOILER_FUEL_TO_
# TABLE_12` covers "Mains Gas"/"Biomass" etc.). 43 = heat from boilers —
# biomass (Table 12, PDF p.189).
_PASHUB_COMMUNITY_FUEL_TO_TABLE_12: Dict[str, int] = {
"Heat from boilers - biomass": 43,
}
def _pashub_community_heating(
heat_source_label: str, fuel_label: str
@ -6589,14 +6604,20 @@ def _pashub_community_heating(
code, Table 12 fuel code) at the mapper boundary (ADR-0015), reusing
`_resolve_community_heating_fuel_code`. An uncovered heat-source label
strict-raises so the dwelling is never silently priced as an ordinary
boiler (issue #1590 follow-up, fixture 507644414148)."""
boiler (issue #1590 follow-up, fixture 507644414148); an uncovered
non-empty fuel label strict-raises too, rather than passing the raw
string through to the calculator's deep `MissingMainFuelType`."""
if heat_source_label not in _PASHUB_COMMUNITY_HEAT_SOURCE_TO_SAP_CODE:
raise UnmappedPasHubLabel("community heat source", heat_source_label)
sap_code = _PASHUB_COMMUNITY_HEAT_SOURCE_TO_SAP_CODE[heat_source_label]
fuel = _resolve_community_heating_fuel_code(
_PASHUB_COMMUNITY_HEAT_SOURCE_TO_ELMHURST[heat_source_label],
fuel_label,
)
fuel = _PASHUB_COMMUNITY_FUEL_TO_TABLE_12.get(fuel_label)
if fuel is None:
fuel = _resolve_community_heating_fuel_code(
_PASHUB_COMMUNITY_HEAT_SOURCE_TO_ELMHURST[heat_source_label],
fuel_label,
)
if fuel is None and fuel_label:
raise UnmappedPasHubLabel("community fuel", fuel_label)
return sap_code, fuel