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 8683e75c..a0180b8e 100644 --- a/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py +++ b/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py @@ -743,12 +743,13 @@ def cert_to_inputs( ) -> CalculatorInputs: """Build a typed `CalculatorInputs` aggregate from an `EpcPropertyData`. - `prices` defaults to the SAP 10.2/10.3 spec-mandated Table 12 values - (`SAP_10_2_SPEC_PRICES`). For parity validation against the cert - corpus's lodged ratings, pass `CERT_CALIBRATION_PRICES` from - `domain.sap.tables.table_12_cert_calibration` — the cert assessor - software diverges from the published spec on unit prices (see slice - S-B9 + docs/sap-spec/PARITY_FINDINGS.md).""" + `prices` defaults to `SAP_10_2_SPEC_PRICES` (SAP 10.2, 14-03-2025 + amendment) and is the only price set the codebase uses, per + ADR-0010. The historical cert-calibration price table was deleted + in P2.3 (commit log) once its bug-masking role was understood; + parity validation now relies on the Validation Cohort filter + (inspection_date ≥ 2025-07-01) rather than a per-cert price + override.""" dim = dimensions_from_cert(epc) window_total_area, window_avg_u = _window_total_area_and_avg_u(epc.sap_windows) exposure = _dwelling_exposure(epc.dwelling_type) diff --git a/packages/domain/src/domain/sap/tables/table_12_cert_calibration.py b/packages/domain/src/domain/sap/tables/table_12_cert_calibration.py deleted file mode 100644 index 48c8564c..00000000 --- a/packages/domain/src/domain/sap/tables/table_12_cert_calibration.py +++ /dev/null @@ -1,129 +0,0 @@ -"""Empirical fuel-price table that matches the cert corpus's lodged -ratings — not the spec-mandated SAP 10.2/10.3 Table 12. - -These prices are an EMPIRICAL CALIBRATION: the cert assessor software -that produced `energy_rating_current` in the corpus appears to use -prices ~10-25% lower than the SAP 10.2 spec mandates (§12.2). Whether -that gap comes from a pre-amendment SAP 10.2 publication, an RdSAP §19 -override, or frozen lodgement-time prices is an open investigation -(see commit S-B9 + dev discussion thread). - -Use this table when running parity validation against -`energy_rating_current` from the corpus — the calculator will then -produce values directly comparable to the cert. For new ratings or -forward-looking calculations, use `domain.sap.tables.table_12` (SAP 10.2 -spec-correct, identical to SAP 10.3). - -The values come verbatim from the prior -`domain.ml.sap_efficiencies._FUEL_UNIT_PRICE` table that the legacy ML -pipeline had been silently using; CO2 factors mirror the SAP 10.2 -spec since the bias regression is cost-driven, not emissions-driven. -""" - -from __future__ import annotations - -from typing import Final - - -UNIT_PRICE_P_PER_KWH: Final[dict[int, float]] = { - # Gas fuels - 1: 3.48, # mains gas - 2: 7.60, # bulk LPG - 3: 10.30, # bottled LPG (main) - 5: 3.48, # bottled LPG (secondary) - 9: 7.60, # LPG SC11F - 7: 0.0, # biogas - # Liquid fuels - 4: 5.44, # heating oil - 71: 7.64, 73: 7.64, 75: 6.10, 76: 47.0, - # Solid fuels - 11: 3.67, 15: 3.64, 12: 4.61, 20: 4.23, 22: 5.81, 23: 5.26, - 21: 3.07, 10: 3.99, - # Electricity - 30: 13.19, # standard tariff - 32: 15.29, # 7h high - 31: 5.50, # 7h low (Economy-7 off-peak) - 34: 14.68, # 10h high - 33: 7.50, # 10h low - 38: 13.67, # 18h high - 40: 7.41, # 18h low - 35: 6.61, # 24h heating - 39: 13.19, - 60: 13.19, - 36: 13.19, - # Heat networks - 51: 4.24, 52: 4.24, 53: 4.24, 54: 4.24, 55: 4.24, 56: 4.24, - 57: 4.24, 58: 4.24, - 41: 4.24, 42: 4.24, 43: 4.24, 44: 4.24, - 45: 2.97, 46: 2.97, 48: 2.97, 50: 0.0, - 47: 2.97, 49: 2.97, -} -_DEFAULT_P_PER_KWH: Final[float] = 3.48 - - -# Lifted from `domain.sap.tables.table_12.API_FUEL_TO_TABLE_12` since the -# API enum → Table 12 code mapping is spec-stable. -API_FUEL_TO_TABLE_12: Final[dict[int, int]] = { - 0: 30, 1: 1, 2: 2, 3: 3, 4: 4, 5: 15, 6: 20, 7: 23, 8: 21, 9: 10, - 10: 30, 11: 42, 12: 43, 13: 44, 14: 11, 15: 12, 16: 22, 17: 9, - 18: 75, 19: 76, 20: 51, 21: 52, 22: 53, 23: 55, 24: 54, 25: 41, - 26: 1, 27: 2, 28: 4, 29: 30, -} - - -def unit_price_p_per_kwh(fuel_code: int | None) -> float: - """Empirical cert-calibration unit price (p/kWh) for the given fuel - code. Use only for parity validation; the SAP-spec answer is in - `domain.sap.tables.table_12.unit_price_p_per_kwh`.""" - if fuel_code is None: - return _DEFAULT_P_PER_KWH - if fuel_code in UNIT_PRICE_P_PER_KWH: - return UNIT_PRICE_P_PER_KWH[fuel_code] - translated = API_FUEL_TO_TABLE_12.get(fuel_code) - if translated is not None and translated in UNIT_PRICE_P_PER_KWH: - return UNIT_PRICE_P_PER_KWH[translated] - return _DEFAULT_P_PER_KWH - - -# Economy-7 low-rate cert-calibration price — empirically matches what -# the cert assessor software appears to charge on storage-heater -# dwellings. -E7_LOW_RATE_P_PER_KWH: Final[float] = 5.50 -STANDARD_ELECTRICITY_P_PER_KWH: Final[float] = 13.19 - - -def _build_cert_calibration_table(): - """Lazy import to avoid the cert_to_inputs ↔ tables import cycle — - the cert_to_inputs module defines `PriceTable`, but this module - can't import from cert_to_inputs because cert_to_inputs imports the - spec table_12. We expose a factory the caller uses to build the - `PriceTable` value at validation-script init time.""" - from domain.sap.rdsap.cert_to_inputs import PriceTable - - # Cert-calibration empirically extends the E7 off-peak set: - # 191-196 direct-electric (boilers etc) — S-B11 finding - # 401-409 electric storage heaters (spec-correct) - # 421-425 high-heat-retention storage (spec-correct) - # 691-696 electric room heaters — S-B14 finding (cert 0340-2394: - # 73m² mid-floor flat, code 691, actual SAP 75, predicted - # 56 before this; cert software applies off-peak to all- - # electric dwellings regardless of heating typology). - cert_calibration_e7_codes = frozenset( - list(range(191, 197)) - + list(range(401, 410)) - + list(range(421, 426)) - + list(range(691, 697)) - ) - return PriceTable( - unit_price_p_per_kwh=unit_price_p_per_kwh, - e7_low_rate_p_per_kwh=E7_LOW_RATE_P_PER_KWH, - standard_electricity_p_per_kwh=STANDARD_ELECTRICITY_P_PER_KWH, - e7_eligible_main_codes=cert_calibration_e7_codes, - ) - - -def cert_calibration_prices(): - """Returns a `PriceTable` populated with the empirical cert- - calibration prices. Call from parity-validation scripts as - `cert_to_inputs(epc, prices=cert_calibration_prices())`.""" - return _build_cert_calibration_table()