Resolve the PasHub PV Connection label to the gov-API credit-gate int 🟩

"Not connected to electricity meter" -> 1 (zero Appendix M credit), "Connected
to dwellings electricity meter" -> 2; the raw string fell through the credit
gate's non-int branch to True, crediting a separately-metered array (issue
#1590 bug 3, fixture 499516101839 -6.9 SAP). Harness MAE 2.571 -> 2.538;
ceiling ratcheted to 2.55.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-14 21:41:04 +00:00
parent f9079eb0ac
commit 56b36ce7f0
2 changed files with 30 additions and 2 deletions

View file

@ -87,7 +87,9 @@ _MIN_WITHIN_HALF: float = 0.12
# Ratcheted 2.64 -> 2.58 by #1590 bug 1 (surveyed PV arrays now reach the
# Appendix M input): observed MAE 2.571 — 507639151843's 13.5-SAP zero-PV-credit
# under-rate closing.
_MAX_SAP_MAE: float = 2.58
# Ratcheted 2.58 -> 2.55 by #1590 bug 3 (PV Connection label -> gov-API int:
# "Not connected" no longer silently credited): observed MAE 2.538.
_MAX_SAP_MAE: float = 2.55
_KNOWN_GAP_REASON = (
"pashub `from_site_notes` mapper does not int-code a main-heating "

View file

@ -367,7 +367,7 @@ class EpcPropertyDataMapper:
is_dwelling_export_capable=general.dwelling_export_capable,
wind_turbines_terrain_type=general.terrain_type,
electricity_smart_meter_present=general.electricity_smart_meter,
pv_connection=renewables.pv_connection,
pv_connection=_pashub_pv_connection_code(renewables.pv_connection),
photovoltaic_arrays=_pashub_pv_arrays(renewables),
photovoltaic_supply=(
PhotovoltaicSupply(
@ -6699,6 +6699,32 @@ _ELMHURST_PV_OVERSHADING_TO_RDSAP: Dict[str, int] = {
}
# PasHub surveyed "PV Connection" label → the gov-API int enum the calculator's
# Appendix M credit gate keys off (`_pv_connected_to_dwelling_meter`): 1 = PV
# present but NOT connected to the dwelling's meter (zero credit — communal /
# separately-metered), 2 = connected (credited). The gate treats any non-int as
# "connected", so an unresolved label silently credits PV the dwelling doesn't
# get to count (issue #1590 bug 3).
_PASHUB_PV_CONNECTION_TO_GOV_API: Dict[str, int] = {
"Not connected to electricity meter": 1,
"Connected to dwellings electricity meter": 2,
}
def _pashub_pv_connection_code(connection_label: Optional[str]) -> Optional[int]:
"""Resolve a PasHub surveyed PV Connection label to the gov-API int enum at
the mapper boundary (ADR-0015). Absent stays None (no PV lodged); a
non-empty label the lookup does not cover strict-raises
`UnmappedPasHubLabel` so the gap is fixed here, never silently credited
downstream."""
if not connection_label:
return None
code = _PASHUB_PV_CONNECTION_TO_GOV_API.get(connection_label)
if code is None:
raise UnmappedPasHubLabel("PV connection", connection_label)
return code
def _pashub_pv_arrays(
renewables: PasHubRenewables,
) -> Optional[List[PhotovoltaicArray]]: