Model/datatypes/epc
Khalim Conn-Kowlessar 15b3df1778 Slice S0380.19: count Elmhurst shower outlets by type (no more hardcoded 1)
Surfaces the lodged shower multiplicity from the Elmhurst Summary §16
on the EPC. Previously `_map_elmhurst_sap_heating` hardcoded:

  electric_shower_count = 1 if has_electric_shower else None
  mixer_shower_count    = 0 if has_electric_shower else None

losing the count for any cert with ≥ 2 outlets. Cert
7800-1501-0922-7127-3563 lodges TWO instantaneous electric showers
("Shower 01" + "Shower 11") but the mapper produced
`electric_shower_count=1`. After this slice:

  electric_shower_count = Σ(s for s in showers if s.outlet_type
                              == "Electric shower")
  mixer_shower_count    = Σ(s for s in showers if s.outlet_type
                              != "Electric shower")

**Cascade SAP effect:** None on cert 7800. Appendix J's eq J16
(`N_ES,per_outlet = N_shower / N_outlets`) and eq J18 (Σ_j E_ES,j)
are symmetric in N_electric_showers when there are no mixer outlets,
so the lodged (64a) kWh and (247a) cost are unchanged. The fix is
correctness-by-construction, not a delta-closer for the negative-band
certs (their +0.69 GBP total-cost gap traces to the gas hot-water
kWh path — separate slice).

**Hand-built fixture updates (5):** the cohort-1 hand-builts at
`domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_*.py`
previously omitted `electric_shower_count` / `mixer_shower_count`
(implicitly None), which matched the mapper's pre-slice None
sentinel. Updated each to the lodged counts the mapper now surfaces:
  000474: 1 mixer  → (0, 1)
  000477: 1 mixer  → (0, 1)
  000480: 1 mixer  → (0, 1)
  000490: 1 mixer  → (0, 1)
  000516: 1 mixer  → (0, 1)
000487 (already at (1, 0) for an electric-shower lodging) unchanged.

Tests:
- `test_summary_7800_two_electric_showers_count_as_two_not_one` —
  pins the multi-shower mapping for cert 7800 (Summary_000890.pdf).
- 5 hand-built field-parity tests
  (`test_from_elmhurst_site_notes_matches_hand_built_*`) now pass at
  the new integer counts instead of None.

Pyright net-zero per file:
- datatypes/epc/domain/mapper.py: 32 (baseline 32)
- backend/documents_parser/tests/test_summary_pdf_mapper_chain.py: 0

Regression baseline: 699 pass + 10 fail (= prior 698 + 10 + 1 new).

Spec refs:
- SAP 10.2 Appendix J §1a — outlet counting drives `N_outlets` used
  in eq J6/J7 (mixer shower water draw) and eq J16/J17/J18 (electric
  shower energy).
- Cert 7800-1501-0922-7127-3563 Summary §16 "Showers" lodgement.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 16:28:46 +00:00
..
domain Slice S0380.19: count Elmhurst shower outlets by type (no more hardcoded 1) 2026-06-01 16:28:46 +00:00
loaders demo generated for use in address2uprn 2026-05-08 14:48:15 +00:00
schema Slice 100c: API path — surface PV arrays + gap-aware glazing lookup 2026-06-01 16:28:45 +00:00
search bolstering testing 2026-04-28 13:46:09 +00:00
surveys Slice S0380.9: multi-array PV support + close cert 0350 to ASHP spec floor 2026-06-01 16:28:46 +00:00
__init__.py testing out rebaselining 2026-02-12 22:25:03 +00:00
construction_age_band.py testing out rebaselining 2026-02-12 22:25:03 +00:00
efficiency.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
floor.py preparing partiy class 2026-02-05 08:54:27 +00:00
fuel.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
heating_controls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
hotwater.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
main_heating.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
property_type_built_form.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
roof.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
walls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
windows.py testing out rebaselining 2026-02-12 22:25:03 +00:00