mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-08-03 05:18:22 +00:00
feat(overlay): enable gas A/B bands — Elmhurst-validated (winter,summer)
Gas A = (90.6, 81.6) [PCDB 18790 Worcester Greenstar 8000 Life], B = (88.0, 79.4) [PCDB 15029 Baxi Duo-tec Combi 24 HE], read off accredited Elmhurst RdSAP10 worksheets (206)/(217). Applied to gas regular (102) + combi (104); gas/LPG/biogas share the codes. A-rated real cert 15017550: +1.78 SAP (the under-credit fix). Oil A/B still pending (no slot). Corpus unmoved; 797 tests green (ADR-0068). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c7edb1df0b
commit
063eb17a89
6 changed files with 49 additions and 16 deletions
|
|
@ -287,13 +287,25 @@ _BAND_TO_TABLE_4B_CODE: dict[tuple[int, BoilerEfficiencyBand], int] = {
|
|||
}
|
||||
|
||||
# A/B exceed Table 4b's 84 % gas / 82–84 % oil ceiling, so they cannot borrow a
|
||||
# Table 4b code — they take SEDBUK-derived `(winter, summer)` slot values that
|
||||
# MUST be validated against an accredited Elmhurst build before they are enabled
|
||||
# (ADR-0068 gated pre-req; ~14.6k A-rated homes move up + ripple into
|
||||
# Recommendations / eligibility). PENDING VALIDATION: intentionally empty — until
|
||||
# the pairs are pinned, an A/B boiler takes no slot and keeps its condensing code
|
||||
# default, so no invented numbers ship.
|
||||
_BAND_SLOT_EFFICIENCY_PCT: dict[tuple[int, BoilerEfficiencyBand], tuple[float, float]] = {}
|
||||
# Table 4b code — they take SEDBUK-derived `(winter, summer)` slot values
|
||||
# validated against an **accredited Elmhurst build** (ADR-0068 gated pre-req).
|
||||
#
|
||||
# GAS (validated 2026-07-29 on Elmhurst RdSAP10, dwelling ref 000567):
|
||||
# A → PCDB 18790 (Worcester Greenstar 8000 Life): worksheet (206)=90.6 / (217)=81.6
|
||||
# B → PCDB 15029 (Baxi Duo-tec Combi 24 HE class): worksheet (206)=88.0 / (217)=79.4
|
||||
# Gas/LPG/biogas share codes 101–119, so one pair per band covers all three; applied
|
||||
# to both gas regular (102) and combi (104). (Enabling A moves ~14.6k A-rated homes
|
||||
# up ~+1–3 SAP — flagged to stakeholders; some cross a band → Recs/eligibility.)
|
||||
#
|
||||
# OIL (124–132): still pending — no oil slot yet, so an oil A/B boiler keeps its
|
||||
# condensing code default (127/130). Oil A/B is a tiny population; a follow-up can
|
||||
# pin it from an oil PCDB product or an oil Elmhurst build. No invented numbers ship.
|
||||
_BAND_SLOT_EFFICIENCY_PCT: dict[tuple[int, BoilerEfficiencyBand], tuple[float, float]] = {
|
||||
(102, BoilerEfficiencyBand.A): (90.6, 81.6),
|
||||
(104, BoilerEfficiencyBand.A): (90.6, 81.6),
|
||||
(102, BoilerEfficiencyBand.B): (88.0, 79.4),
|
||||
(104, BoilerEfficiencyBand.B): (88.0, 79.4),
|
||||
}
|
||||
|
||||
|
||||
def band_seasonal_efficiency_pct(
|
||||
|
|
|
|||
BIN
sap worksheets/A rated boiler/Summary_000567.pdf
Normal file
BIN
sap worksheets/A rated boiler/Summary_000567.pdf
Normal file
Binary file not shown.
BIN
sap worksheets/A rated boiler/U985-0001-000567 (1).pdf
Normal file
BIN
sap worksheets/A rated boiler/U985-0001-000567 (1).pdf
Normal file
Binary file not shown.
BIN
sap worksheets/B rated boiler/Summary_000567.pdf
Normal file
BIN
sap worksheets/B rated boiler/Summary_000567.pdf
Normal file
Binary file not shown.
BIN
sap worksheets/B rated boiler/U985-0001-000567 (1).pdf
Normal file
BIN
sap worksheets/B rated boiler/U985-0001-000567 (1).pdf
Normal file
Binary file not shown.
|
|
@ -42,15 +42,33 @@ def test_c_and_below_bands_resolve_to_the_table_4b_pair(
|
|||
assert band_seasonal_efficiency_pct(base_code, band) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("base_code", "band", "expected"),
|
||||
[
|
||||
# Gas A/B validated against accredited Elmhurst (ADR-0068): A → PCDB 18790
|
||||
# (Worcester Greenstar 8000 Life) 90.6/81.6; B → PCDB 15029 (Baxi Duo-tec
|
||||
# Combi 24 HE) 88.0/79.4. Gas/LPG/biogas share codes — one pair per band on
|
||||
# both regular (102) and combi (104).
|
||||
(102, BoilerEfficiencyBand.A, (90.6, 81.6)),
|
||||
(104, BoilerEfficiencyBand.A, (90.6, 81.6)),
|
||||
(102, BoilerEfficiencyBand.B, (88.0, 79.4)),
|
||||
(104, BoilerEfficiencyBand.B, (88.0, 79.4)),
|
||||
],
|
||||
)
|
||||
def test_gas_a_and_b_bands_use_the_elmhurst_validated_slot(
|
||||
base_code: int, band: BoilerEfficiencyBand, expected: tuple[float, float]
|
||||
) -> None:
|
||||
# These exceed Table 4b's 84% ceiling (the A under-credit the fix removes).
|
||||
assert band_seasonal_efficiency_pct(base_code, band) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize("band", [BoilerEfficiencyBand.A, BoilerEfficiencyBand.B])
|
||||
@pytest.mark.parametrize("base_code", [102, 104, 127, 130])
|
||||
def test_a_and_b_bands_are_pending_elmhurst_validation(
|
||||
@pytest.mark.parametrize("base_code", [127, 130])
|
||||
def test_oil_a_and_b_bands_are_pending_validation(
|
||||
base_code: int, band: BoilerEfficiencyBand
|
||||
) -> None:
|
||||
# A/B exceed Table 4b's 84% ceiling — they are judgement values that MUST be
|
||||
# pinned against an accredited Elmhurst build before they are enabled
|
||||
# (ADR-0068 gated pre-req). Until then: no slot, so an A/B boiler keeps its
|
||||
# condensing code default (no invented numbers ship).
|
||||
# Oil A/B not yet validated — no slot, so an oil A/B boiler keeps its
|
||||
# condensing code default (127/130). No invented numbers ship (ADR-0068).
|
||||
assert band_seasonal_efficiency_pct(base_code, band) is None
|
||||
|
||||
|
||||
|
|
@ -77,6 +95,10 @@ def test_non_banded_boilers_never_take_a_slot(
|
|||
("Gas boiler, combi", BoilerEfficiencyBand.G, (66.0, 57.0)),
|
||||
("Oil boiler, regular", BoilerEfficiencyBand.E, (71.0, 59.0)),
|
||||
("Oil boiler, combi", BoilerEfficiencyBand.D, (77.0, 68.0)),
|
||||
# Elmhurst-validated A/B upside on gas (the A under-credit fix).
|
||||
("Gas boiler, regular", BoilerEfficiencyBand.A, (90.6, 81.6)),
|
||||
("Gas boiler, combi", BoilerEfficiencyBand.A, (90.6, 81.6)),
|
||||
("Gas boiler, combi", BoilerEfficiencyBand.B, (88.0, 79.4)),
|
||||
],
|
||||
)
|
||||
def test_overlay_sets_the_band_efficiency_slot_on_gas_and_oil_boilers(
|
||||
|
|
@ -96,9 +118,8 @@ def test_overlay_sets_the_band_efficiency_slot_on_gas_and_oil_boilers(
|
|||
[
|
||||
# No band → no slot (today's behaviour: keep the condensing code default).
|
||||
("Gas boiler, combi", None),
|
||||
# A/B pending Elmhurst → no slot yet.
|
||||
("Gas boiler, combi", BoilerEfficiencyBand.A),
|
||||
# C on gas regular equals the code default — still set, but a no-op value.
|
||||
# Oil A/B still pending Elmhurst → no slot yet.
|
||||
("Oil boiler, combi", BoilerEfficiencyBand.A),
|
||||
# Non-banded boilers ignore the band letter entirely.
|
||||
("Electric boiler", BoilerEfficiencyBand.D),
|
||||
("Solid fuel boiler", BoilerEfficiencyBand.G),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue