From 6d256ab2bce6d2d997ed88209cdebacabdd709c7 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 18 May 2026 14:59:09 +0000 Subject: [PATCH] slice S-B8: extend E7 off-peak rate to HW for E7-tariff dwellings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the main heating is electric storage / direct-electric (codes 191-196, 401-409, 421-425), the cert almost always carries an Economy-7 tariff and the immersion HW cylinder runs on the off-peak timer. Bill HW at the 7h-low rate (5.5 p/kWh) in that case, falling back to the lower of {7h-low, water_heating_fuel rate} so we never over-charge an HW fuel that's already cheaper than off-peak. 100-cert parity probe: MAE 4.90 → 4.66 (-0.24) bias -1.44 → -0.70 (over-correction halved) within ±3: 46% → 48% within ±5: 67% → 68% within ±10: 93% → 94% Co-Authored-By: Claude Opus 4.7 --- .../domain/src/domain/sap/rdsap/cert_to_inputs.py | 13 +++++++++---- .../domain/sap/rdsap/tests/test_cert_to_inputs.py | 6 ++++-- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py b/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py index 1e6dd84e..38df234e 100644 --- a/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py +++ b/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py @@ -383,10 +383,15 @@ def _space_heating_fuel_cost_gbp_per_kwh(main: Optional[MainHeatingDetail]) -> f def _hot_water_fuel_cost_gbp_per_kwh( main: Optional[MainHeatingDetail], water_heating_fuel: Optional[int] ) -> float: - """Hot water bills at the *water-heating* fuel's rate — distinct from - the main heating fuel for gas-heated dwellings whose DHW runs off an - electric immersion. Falls back to the main fuel when the cert - doesn't lodge a separate water fuel.""" + """Hot water bills at the *water-heating* fuel's rate. Special case: + an E7-tariff dwelling (electric storage / direct-electric main + heating) running an electric immersion HW cylinder bills HW at the + 7h-low rate too, since these households typically run the immersion + on the off-peak timer — RdSAP convention. Falls back to the main + fuel when the cert doesn't lodge a separate water fuel.""" + is_e7 = _is_electric_storage_or_direct(main) + if is_e7 and (water_heating_fuel is None or fuel_unit_price_p_per_kwh(water_heating_fuel) > _E7_LOW_RATE_P_PER_KWH): + return _E7_LOW_RATE_P_PER_KWH * _PENCE_TO_GBP if water_heating_fuel is not None: return fuel_unit_price_p_per_kwh(water_heating_fuel) * _PENCE_TO_GBP return _fuel_cost_gbp_per_kwh(main) diff --git a/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py b/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py index c06ec41b..87e6c68a 100644 --- a/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py +++ b/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py @@ -335,9 +335,11 @@ def test_electric_storage_heater_space_heating_at_off_peak_rate() -> None: # Act inputs = cert_to_inputs(epc) - # Assert + # Assert — RdSAP convention: when an E7 dwelling's HW runs on + # electric immersion, the immersion is presumed to be on the + # off-peak timer, so HW bills at the 7h-low rate too. assert inputs.space_heating_fuel_cost_gbp_per_kwh == 0.055 - assert inputs.hot_water_fuel_cost_gbp_per_kwh == 0.1319 + assert inputs.hot_water_fuel_cost_gbp_per_kwh == 0.055 assert inputs.other_fuel_cost_gbp_per_kwh == 0.1319