§4 HW slice 3: docs — SPEC_COVERAGE row + Remaining work + golden note

- SPEC_COVERAGE §4 row: closed (combi-gas single-rate) — PCDB Table
  3b + Eq D1 cascade. 000474 + 000490 HW kWh ≤0.1% of PDF.
  Remaining §4 work list refreshed: storage / FGHRS rows, Table 3c
  two-profile, Electric CPSU Appendix F, instant electric shower,
  Appendix L lighting (separate ticket per memory).
- §4 slice progress table: (61)m row updated with `760e25de` commit
  pointer + dual sourcing (Table 3a default + PCDB Table 3b row 1
  override).
- test_golden_fixtures.py: SAP_TOLERANCE stays ±11 — §4 HW closure
  doesn't shift the oil-heated golden certs because they aren't PCDB
  Table-3b-listed. Comment block updated with the §4 slice 2 note.

No code changes — docs + tolerance comment only.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-21 22:58:16 +00:00
parent 02fc9e4d47
commit c9eb231a9c
2 changed files with 18 additions and 11 deletions

View file

@ -2,7 +2,7 @@
Tracks which sections of the SAP 10.2 specification are implemented in `packages/domain/src/domain/sap/`. Per ADR-0009 the calculator is built from the spec, not reverse-engineered from cert data. This doc is the worksheet-driven roadmap for what remains.
Updated 2026-05-21 after §8c (slices `cf28eec4``f3797066`), §8f (`43cc16bc`), §9a single-main slices (`2b5fc6a5``380b6781`), PCDB Table 105 integration (`fe04cd3a``a104dd55`), PCDB fixture lodgement (`1b43c95c``15d6b781`), and §10a Fuel costs (`0f255165``adfa7f60`).
Updated 2026-05-21 after §8c (slices `cf28eec4``f3797066`), §8f (`43cc16bc`), §9a single-main slices (`2b5fc6a5``380b6781`), PCDB Table 105 integration (`fe04cd3a``a104dd55`), PCDB fixture lodgement (`1b43c95c``15d6b781`), §10a Fuel costs (`0f255165``adfa7f60`), and §4 HW PCDB Table 3b + Equation D1 (`760e25de`, `02fc9e4d`).
The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xlsx`](../../2026-05-19-17-18%20RdSap10Worksheet.xlsx) at the repo root — each line ref `(1)..(486)` maps to a cell. The worksheet sub-modules under `packages/domain/src/domain/sap/worksheet/` implement those line refs directly; Elmhurst worksheets validate end-to-end via `tests/_elmhurst_worksheet_*.py`.
@ -13,7 +13,7 @@ The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xls
| 1 | 1120 (approx) | Dimensions | `worksheet/dimensions.py` | **Full** | Porches, conservatories, RIR deferred per ADR-0009 |
| 2 | 121206 (approx) | Ventilation | `worksheet/ventilation.py` | Partial | No mechanical ventilation (MVHR/MEV), no wind-shelter factor, no pressure-test override (worksheet lines 17-18), no AP4 override (worksheet line 19) |
| 3 | 121207 | Heat transmission | `worksheet/heat_transmission.py` | **Full (non-RR)** | LINE_31/33/36/37 exact for both non-RR Elmhurst fixtures (000474, 000490). Suspended-timber + Table 20 exposed-floor routes wired. RR sub-areas (gable/slope/stud-wall) deferred until `SapRoomInRoof` carries them. Global y-factor (Table R2 per-junction deferred). |
| 4 | 207304 | Hot water + Appendix J | `worksheet/water_heating.py` (new) + legacy `domain.ml.demand.predicted_hot_water_kwh` (calculator still calls this) | **Happy-path done** — see slice progress below. Worksheet-driven module lands line refs (42)..(65) for the combi-gas-boiler population (~70% of corpus). Cylinder + solar + renewables branches deferred. Calculator.py not yet wired to new module — next step. |
| 4 | 207304 | Hot water + Appendix J + Appendix D | `worksheet/water_heating.py` + cert_to_inputs `_water_heating_worksheet_and_gains` + `_apply_water_efficiency` | **Closed for combi-gas — PCDB Table 3b combi loss + Equation D1 monthly cascade wired.** Worksheet line refs (42)..(65) + Appendix D §D2.1 (2) Equation D1 (`water_efficiency_monthly_via_equation_d1`) + Appendix J Table 3b row 1 (`combi_loss_monthly_kwh_table_3b_row_1_instantaneous`). 000474 + 000490 HW kWh match PDF to ≤0.1%. cert_to_inputs splits the §4 worksheet from the efficiency divisor: (45..65) runs early so §5 has (65)m heat gains; HW fuel kWh computed after §8 produces (98c)m for the Eq D1 cascade. PCDB Table 105 parser exposes 5 new combi-loss fields (separate_dhw_tests, r1, F1, F2, F3 + subsidiary_type + store_type) per BRE PCDF Spec v1.0 §7.11. **Deferred**: Cylinder + solar + WWHRS + PV diverter + FGHRS branches (no fixture yet); Table 3b storage / FGHRS rows (no fixture yet); Table 3c two-profile boilers (no fixture yet); Electric CPSU Appendix F path (no fixture yet). |
| 5 | Internal gains + Appendix L | `worksheet/internal_gains.py` | **Full** | Worksheet-driven (66)..(73), Table 5 Column A, Table 5a 9-row dispatch + heating-season mask, Appendix L L1-L12 with RdSAP §12-1 bulb defaults + Table 6d Z_L (light access factor). Wired into `calculator.py` via `cert_to_inputs`. Six Elmhurst fixtures conform end-to-end to ≤0.6% lighting / ≤0.2 W (73). |
| 6 | Solar gains + Tables 6b/6c/6d + Appendix U | `worksheet/solar_gains.py` | **Full** | Worksheet-driven (74)..(83). Table 6b g⊥ via manufacturer `window_transmission_details` first, Table 6b code lookup fallback; Table 6c FF by frame_material substring; Table 6d Z (heating column) by `OvershadingCategory`; roof windows pitched at RdSAP10 Table 24 default 45°; rooflights horizontal per §U3.2 p128. `solar_gains_from_cert` wired into `cert_to_inputs` + `calculator.py`. Six Elmhurst fixtures conform end-to-end to ≤5e-3 W on (83) + (84). |
| 7 | Mean internal temperature | `worksheet/mean_internal_temperature.py` | **Full** | Worksheet-driven (85)..(94) via `mean_internal_temperature_monthly`. Table 9c steps 1-9 sequential (per-zone η: (86) η_living at Ti=T_h1, (89) η_elsewhere at Ti=T_h2, (94) η_whole at Ti=(93)). Table 9b u-formula consumes weighted R for two-main case 1 (single-main is default). Wired into `calculator.py` + `cert_to_inputs` via two new `CalculatorInputs` fields. Six Elmhurst fixtures conform end-to-end to ≤5e-3 °C on all 9 line tuples + 2 scalars per month (588 assertions). Table 4e adj defaults 0 (cert-side mapping deferred — all 6 fixtures = 0); two-main case 2 (different parts heated separately) deferred. |
@ -81,22 +81,23 @@ Status now: 100-cert MAE 4.49, 300-cert MAE 5.45, bias near zero (±0.2). Worksh
| (47)(56) | Storage / HIU loss | Combi zero-branch only; cylinder paths deferred | — |
| (57)m | Dedicated solar storage | Combi zero-branch only; solar HW deferred | — |
| (59)m | Primary loss | Combi zero-branch only; boiler+cylinder deferred | — |
| (61)m | Combi loss | Table 3a row "time-clock keep-hot" only | `bfba610b` |
| (61)m | Combi loss | Table 3a default + PCDB Table 3b row 1 (instantaneous non-storage) override | `bfba610b`, `760e25de` |
| (62)m | Total demand | ✅ | `bfba610b` |
| (63a-d) | WWHRS/PV/Solar/FGHRS reductions | Zero-only — non-zero paths deferred | `feef8198` |
| (64)m | Output from water heater | ✅ (with max-clamp) | `feef8198` |
| (64a)m | Electric shower energy | Zero-only — non-zero path deferred | — |
| (65)m | Heat gains | ✅ | `43da3ea0` |
**Happy path closes both non-RR Elmhurst fixtures to <1e-3 kWh end-to-end on lines (42)..(65)** (000474's PCDB-backed Table 3b combi loss is the one hand-lodged value).
**Happy path closes both non-RR Elmhurst fixtures to <1e-3 kWh end-to-end on lines (42)..(65)**. (61)m PCDB Table 3b row 1 lands the 000474 combi loss within 0.02% of PDF arithmetic. **§4 HW slice 2 update:** Equation D1 monthly cascade (Appendix D §D2.1 (2)) wired post-§8 closes HW *fuel* kWh 000474: 2622 2292 (matches PDF 2292 to 0.1%); 000490: 3028 2847 (matches PDF 2851 to 0.1%). Closes the residual §10a "section 4 next ticket" debt named in `project_section_4_hw_next_ticket` memory + ADR-0010 §4-amendment of §10a slice 3.
### Remaining §4 work
1. **Orchestrator** `water_heating_from_cert(epc, ...)` that wires the leaf functions, mirroring `heat_transmission_from_cert` for §3.
2. **Integrate with `calculator.py`** — replace the legacy `domain.ml.demand.predicted_hot_water_kwh` call.
3. **End-to-end SAP score** validation against the worksheets — the real e2e test the user has been asking for.
4. **Cylinder + solar + renewables paths** for full population coverage (cylinders, FGHRS, WWHRS, PV-diverter).
5. **PCDB-backed Table 3b/3c combi loss** for tested boilers (000474 sits here).
1. **Cylinder + solar + renewables paths** for full population coverage (cylinders, FGHRS, WWHRS, PV-diverter, solar HW). Currently zero-branch placeholders.
2. **PCDB Table 3b storage / FGHRS rows** (other than row 1) — the impl exposes profile_flag + r1/F1/F2/F3 fields but only row 1 (instantaneous non-storage) computes. Storage variants raise `NotImplementedError`-equivalent (fall through to Table 3a) until a fixture exercises.
3. **PCDB Table 3c** (two-profile boilers, separate_dhw_tests = 2 or 3) — Table 3c uses r1, F2, F3, DVF (daily volume factor); parser exposes the fields, formula pending.
4. **Electric CPSU → Appendix F** path for water-eff cascade.
5. **(64a) Instant electric shower** kWh routing — line currently always 0 from `_hot_water_fuel_kwh_per_yr`; wire when an electric-shower cert lodges.
6. **Appendix L lighting predictor** (`domain.ml.demand.predicted_lighting_kwh`) — separate ticket per memory `project_section_4_hw_next_ticket` "secondary upstream". 000474 lights 528 kWh/yr vs ~169 back-derived from PDF cost; tightening drops the 000474 cost residual from +9.2% closer to zero.
## §5 — slice progress (xlsx rows 305332)

View file

@ -62,8 +62,14 @@ _FIXTURES_DIR = Path(__file__).parent / "fixtures" / "golden"
# heated (0240 -11 SAP, 0390 -10 SAP). The lodged SAP scores in the
# golden corpus were computed by the cert assessor against Table 12
# (or earlier) prices; comparing those to our Table 32 calculator is
# mixing spec versions per ADR-0010 §3 Validation Cohort. Tightens
# when golden corpus refresh + Validation Cohort filter land.
# mixing spec versions per ADR-0010 §3 Validation Cohort.
#
# **§4 HW slice 2 update:** still ±11. The §4 HW closure (PCDB Table 3b
# combi loss + Equation D1 monthly water-eff cascade) tightens 000474
# / 000490 HW kWh to ≤0.1% of PDF, but oil-heated golden certs aren't
# PCDB-Table-3b-listed so their residuals are unchanged from §10a.
# Tightens further when golden corpus refresh + Validation Cohort
# filter land.
_SAP_TOLERANCE = 11
_PE_TOLERANCE_KWH_PER_M2 = 30.0