mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice S0380.11: resolve zero-shower lodgings to count=0 (closes cert 2225)
Cert 2225-3062-8205-2856-7204 lodges **zero showers** in its Summary §1x Baths and Showers block. The Summary mapper at `mapper.py:3536-3537` predicated the shower-count assignment on `has_electric_shower`: for cohort certs with no electric shower the counts collapsed to None — but cert 2225 has no showers at all, and the cascade's None-handling defaults to 1 mixer shower (over-counting HW kWh by ~66 against the worksheet (64)/(216) target). Same disposition the API path received in slice 102f-prep.8 (commit1d5183c6, "API mapper resolves shower_outlets=None → 0 mixers") — extending it to the Summary mapper. Scope-limited fix: zero-shower lodgings resolve to **explicit 0** counts (not None) so the cascade does not default-assume a mixer. Non-zero shower lodgings keep their existing convention (None for non-electric → cascade derives count from `shower_outlets`) so the 5 boiler-cohort hand-built parity tests (`test_from_elmhurst_site_notes_matches_hand_built_*`) stay GREEN. Forcing function: cert 2225 first-attempt Summary SAP closes from Δ -0.3079 to Δ **+0.0441** — within the ±0.07 ASHP-cohort spec floor. Cohort closure status (5 of 7 ASHP certs now at spec floor): cert Δ vs worksheet spec floor? 0380 +0.0594 ✓ 0350 +0.0458 ✓ 2225 +0.0441 ✓ ← this slice 2636 +0.4873 ✗ (cantilever + alt-wall; next slice) 3800 +0.0442 ✓ 9285 +0.0502 ✓ 9418 +2.5973 ✗ (Daikin EDLQ05CAV3, distinct PCDB) Added two tests: - `test_summary_2225_no_showers_lodged_resolves_to_zero_counts` — unit-level pin that no-shower lodgings produce explicit 0 counts. - `test_summary_2225_full_chain_sap_within_spec_floor_of_worksheet` — Layer-4 chain test at ±0.07. Pyright net-zero on both edited files (mapper.py 32 baseline). Regression suite: 682 pass + 10 fail (handover baseline 669 + 10 + 13 new GREEN tests across S0380.2..S0380.11). The 5 boiler hand- built parity tests confirmed still GREEN — the refinement deliberately preserves their convention by only flipping the zero- shower case. Spec refs: - Slice 102f-prep.8 (commit1d5183c6) — API-path precedent. - SAP 10.2 Appendix J — shower energy accounting (electric vs mixer routing); mixer showers draw from the HW system and contribute to HW kWh; electric showers are §J line 64a (separate energy stream). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
11e0279dce
commit
29cfdf6461
2 changed files with 68 additions and 2 deletions
|
|
@ -62,6 +62,7 @@ _SUMMARY_000899_PDF = _FIXTURES / "Summary_000899.pdf"
|
|||
_SUMMARY_000903_PDF = _FIXTURES / "Summary_000903.pdf"
|
||||
_SUMMARY_000901_PDF = _FIXTURES / "Summary_000901.pdf" # cert 3800
|
||||
_SUMMARY_000904_PDF = _FIXTURES / "Summary_000904.pdf" # cert 9285
|
||||
_SUMMARY_000900_PDF = _FIXTURES / "Summary_000900.pdf" # cert 2225
|
||||
|
||||
# GOV.UK EPB API JSON for cert 001479 — the API-path counterpart of the
|
||||
# Summary_001479.pdf fixture. Together they drive the API ≡ Summary
|
||||
|
|
@ -713,6 +714,55 @@ def test_summary_0350_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
|||
assert abs(result.sap_score_continuous - worksheet_unrounded_sap) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_summary_2225_no_showers_lodged_resolves_to_zero_counts() -> None:
|
||||
# Arrange — cert 2225-3062-8205-2856-7204's Summary §1x Baths and
|
||||
# Showers block lodges 0 baths and ZERO showers (no shower rows at
|
||||
# all). The Summary mapper's existing logic at
|
||||
# `mapper.py:3536-3537` predicates the count assignment on
|
||||
# `has_electric_shower`: when no electric shower is detected the
|
||||
# counts collapse to None — but cert 2225 has no showers at all,
|
||||
# not "non-electric showers". The None values then drive the
|
||||
# cascade's default-1-mixer assumption, over-counting HW kWh.
|
||||
# Same disposition the API path received in slice 102f-prep.8
|
||||
# (commit 1d5183c6: "API mapper resolves shower_outlets=None →
|
||||
# 0 mixers").
|
||||
pages = _summary_pdf_to_textract_style_pages(_SUMMARY_000900_PDF)
|
||||
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||
# Pre-condition: §1x lodges zero showers (proves the test sees
|
||||
# the same no-showers fixture the cascade does).
|
||||
assert len(site_notes.baths_and_showers.showers) == 0
|
||||
|
||||
# Act
|
||||
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||
|
||||
# Assert — zero-shower lodgings resolve to explicit 0 counts (not
|
||||
# None) so the cascade does not default-assume a mixer.
|
||||
assert epc.sap_heating.electric_shower_count == 0
|
||||
assert epc.sap_heating.mixer_shower_count == 0
|
||||
|
||||
|
||||
def test_summary_2225_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Arrange — cert 2225-3062-8205-2856-7204 (Summary_000900.pdf):
|
||||
# Mitsubishi PUZ-WM50VHA, single-bp single-array PV (3.28 kWp SE),
|
||||
# ZERO showers lodged. Worksheet "SAP value" 88.7921. Slice
|
||||
# S0380.11 closed the zero-shower defaulting bug (None → 0 mixers
|
||||
# for cohort certs that lodge no showers); cert 2225 was the
|
||||
# forcing function. Same disposition the API path received in
|
||||
# slice 102f-prep.8 (commit 1d5183c6).
|
||||
pages = _summary_pdf_to_textract_style_pages(_SUMMARY_000900_PDF)
|
||||
site_notes = ElmhurstSiteNotesExtractor(pages).extract()
|
||||
epc = EpcPropertyDataMapper.from_elmhurst_site_notes(site_notes)
|
||||
|
||||
# Act
|
||||
result = calculate_sap_from_inputs(
|
||||
cert_to_inputs(epc, prices=SAP_10_2_SPEC_PRICES)
|
||||
)
|
||||
|
||||
# Assert — ±0.07 ASHP-cohort spec-floor tolerance.
|
||||
worksheet_unrounded_sap = 88.7921
|
||||
assert abs(result.sap_score_continuous - worksheet_unrounded_sap) < _ASHP_COHORT_CHAIN_TOLERANCE
|
||||
|
||||
|
||||
def test_summary_3800_full_chain_sap_within_spec_floor_of_worksheet() -> None:
|
||||
# Arrange — cert 3800-8515-0922-3398-3563 (Summary_000901.pdf /
|
||||
# dr87-0001-000901.pdf) is the third ASHP cohort cert to close on
|
||||
|
|
|
|||
|
|
@ -3533,8 +3533,24 @@ def _map_elmhurst_sap_heating(survey: ElmhurstSiteNotes) -> SapHeating:
|
|||
mh.secondary_heating_sap_code,
|
||||
),
|
||||
number_baths=survey.baths_and_showers.number_of_baths,
|
||||
electric_shower_count=1 if has_electric_shower else None,
|
||||
mixer_shower_count=0 if has_electric_shower else None,
|
||||
# Zero-shower lodgings resolve to explicit 0 (not None) so the
|
||||
# cascade doesn't default-assume a mixer — same disposition
|
||||
# the API path received in slice 102f-prep.8 ("API mapper
|
||||
# resolves shower_outlets=None → 0 mixers") on cohort cert
|
||||
# 2225. Non-zero shower lodgings keep the hand-built-fixture
|
||||
# convention (None for non-electric → cascade derives count
|
||||
# from `shower_outlets` instead) so the boiler-cohort parity
|
||||
# tests in this file stay GREEN.
|
||||
electric_shower_count=(
|
||||
0
|
||||
if not survey.baths_and_showers.showers
|
||||
else (1 if has_electric_shower else None)
|
||||
),
|
||||
mixer_shower_count=(
|
||||
0
|
||||
if not survey.baths_and_showers.showers
|
||||
else (0 if has_electric_shower else None)
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue