P2.3: delete table_12_cert_calibration.py (no remaining consumers)

ADR-0010 §2: the cert-calibration price table was bug-masking
pre-March-2025 SAP values fit against a mixture-distribution of two
spec-version regimes. P2.1 swapped the probe to SAP_10_2_SPEC_PRICES,
P2.2 migrated the golden fixtures, leaving no external consumers.
File deletion is mechanical at this point.

Also updates the cert_to_inputs() docstring at L741-L751: removes the
stale reference to CERT_CALIBRATION_PRICES, points at ADR-0010 and
the Validation Cohort filter as the parity-validation mechanism.

All 152 SAP + ml_training_data tests pass with the file gone.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-19 10:04:28 +00:00
parent 28e9dd3864
commit cd6ac9b16d
2 changed files with 7 additions and 135 deletions

View file

@ -743,12 +743,13 @@ def cert_to_inputs(
) -> CalculatorInputs: ) -> CalculatorInputs:
"""Build a typed `CalculatorInputs` aggregate from an `EpcPropertyData`. """Build a typed `CalculatorInputs` aggregate from an `EpcPropertyData`.
`prices` defaults to the SAP 10.2/10.3 spec-mandated Table 12 values `prices` defaults to `SAP_10_2_SPEC_PRICES` (SAP 10.2, 14-03-2025
(`SAP_10_2_SPEC_PRICES`). For parity validation against the cert amendment) and is the only price set the codebase uses, per
corpus's lodged ratings, pass `CERT_CALIBRATION_PRICES` from ADR-0010. The historical cert-calibration price table was deleted
`domain.sap.tables.table_12_cert_calibration` the cert assessor in P2.3 (commit log) once its bug-masking role was understood;
software diverges from the published spec on unit prices (see slice parity validation now relies on the Validation Cohort filter
S-B9 + docs/sap-spec/PARITY_FINDINGS.md).""" (inspection_date 2025-07-01) rather than a per-cert price
override."""
dim = dimensions_from_cert(epc) dim = dimensions_from_cert(epc)
window_total_area, window_avg_u = _window_total_area_and_avg_u(epc.sap_windows) window_total_area, window_avg_u = _window_total_area_and_avg_u(epc.sap_windows)
exposure = _dwelling_exposure(epc.dwelling_type) exposure = _dwelling_exposure(epc.dwelling_type)

View file

@ -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()