test(pv): credit PV only when connected to dwelling meter (pv_connection) 🟥

RdSAP 10 §11.1 / SAP 10.2 Appendix M: PV is included in a dwelling's
assessment only if connected to the dwelling's own electricity meter. The
gov-API pv_connection enum encodes this — 0=no PV, 1=present-but-not-
connected, 2=connected. Corpus-validated (57 PV certs: pv_connection=1 MAE
4.48->1.22 without credit, 0/5 need it; pv_connection=2 needs it, MAE 0.98
vs 10.29) and Elmhurst-proven (connected SAP 87 vs not-connected 74).

cert_to_inputs currently credits a pv_connection=1 array; the test pins that
it must contribute zero generation. Adds pv_connection to make_minimal_sap10_epc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-29 13:32:20 +00:00
parent 98ba8d89dc
commit 775232b4e7
2 changed files with 38 additions and 0 deletions

View file

@ -267,6 +267,7 @@ def make_minimal_sap10_epc(
sap_heating: Optional[SapHeating] = None,
photovoltaic_arrays: Optional[list[PhotovoltaicArray]] = None,
photovoltaic_supply_percent_roof_area: Optional[int] = None,
pv_connection: Optional[int] = None,
mains_gas: bool = True,
electricity_smart_meter_present: bool = False,
gas_smart_meter_present: bool = False,
@ -308,6 +309,7 @@ def make_minimal_sap10_epc(
sap_energy_source=SapEnergySource(
mains_gas=mains_gas,
meter_type="Single",
pv_connection=pv_connection,
pv_battery_count=pv_battery_count,
wind_turbines_count=wind_turbines_count,
gas_smart_meter_present=gas_smart_meter_present,

View file

@ -40,6 +40,7 @@ from domain.sap10_ml.tests._fixtures import (
make_floor_dimension,
make_main_heating_detail,
make_minimal_sap10_epc,
make_pv_array,
make_sap_heating,
make_window,
)
@ -8387,3 +8388,38 @@ def test_heat_pump_water_scop_not_applied_to_separate_immersion_dhw() -> None:
# heat pump or a gas boiler (the HP water SCOP does not apply to it).
assert hp_fuel > 0.0
assert abs(hp_fuel - boiler_fuel) <= 1e-6
def test_pv_credited_only_when_connected_to_dwelling_meter_per_pv_connection() -> None:
# RdSAP 10 §11.1 / SAP 10.2 Appendix M: PV-generated electricity is
# included in a dwelling's assessment ONLY IF the array is connected to
# the dwelling's own electricity meter; an unconnected (communal /
# separately-metered) array contributes nothing to the dwelling's energy
# cost, CO2 or primary energy. The gov-API `sap_energy_source.pv_connection`
# enum encodes this: 0 = no PV, 1 = present but NOT connected, 2 = connected.
#
# Validated on the RdSAP-21.0.1 corpus (57 PV certs): every pv_connection=1
# cert reconciles BETTER without the credit (MAE 4.48 -> 1.22, 0/5 need it),
# while pv_connection=2 certs need it (MAE 0.98 vs 10.29 without). Accredited
# Elmhurst proof: an identical dwelling rates SAP 87 with "Connected to
# Dwelling = Yes" (credit -£167) vs SAP 74 with "No" (credit £0).
array = [make_pv_array(peak_power=3.0)]
def _gen(pv_connection: int) -> float:
epc = make_minimal_sap10_epc(
dwelling_type="Mid-terrace house",
total_floor_area_m2=70.0,
habitable_rooms_count=3,
country_code="ENG",
photovoltaic_arrays=array,
is_dwelling_export_capable=True,
pv_connection=pv_connection,
)
return cert_to_inputs(epc).pv_generation_kwh_per_yr
# pv_connection=2 (connected to the dwelling's meter) → PV serves the
# dwelling and is credited.
assert _gen(2) > 0.0
# pv_connection=1 (present but NOT connected to the dwelling's meter) →
# the array contributes nothing to this dwelling's SAP.
assert _gen(1) == 0.0