From d90827446a56e0e4b82c2b383690966dfdc52b67 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 20 May 2026 15:18:46 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20sweep=20stale=20handover,=20mark=20?= =?UTF-8?q?=C2=A73=20Full,=20scaffold=20=C2=A74=20slice=20plan?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit §3 close (LINE_31/33/36/37 exact for both non-RR Elmhurst worksheets) is now landed across slices 344a9c9d..cf244762. HANDOVER_S3_CLOSE.md was written as a mid-stream working brief; with §3 done it now creates doc rot, so it's removed in favour of SPEC_COVERAGE.md as the single source of truth. SPEC_COVERAGE.md updates: - §3 marked Full (non-RR); RR sub-area deferral noted - §4 carries the ordered slice plan for the worksheet-driven rewrite (xlsx rows 207–304, line refs (42)..(65)) - Hierarchy callout: the canonical SAP10.2 algorithm lives in the repo-root xlsx, not in any handover doc Co-Authored-By: Claude Opus 4.7 --- docs/sap-spec/HANDOVER_S3_CLOSE.md | 149 ----------------------------- docs/sap-spec/SPEC_COVERAGE.md | 39 ++++++-- 2 files changed, 32 insertions(+), 156 deletions(-) delete mode 100644 docs/sap-spec/HANDOVER_S3_CLOSE.md diff --git a/docs/sap-spec/HANDOVER_S3_CLOSE.md b/docs/sap-spec/HANDOVER_S3_CLOSE.md deleted file mode 100644 index 228c065c..00000000 --- a/docs/sap-spec/HANDOVER_S3_CLOSE.md +++ /dev/null @@ -1,149 +0,0 @@ -# Handover — Close §3, then Table 11 Secondary Heating - -**Audience:** Fresh agent continuing the deterministic SAP 10.2 calculator -(`packages/domain/src/domain/sap/`). Read this document first, then skim -the two key source files listed below. - ---- - -## What we're building - -A deterministic SAP 10.2 calculator that replicates cert-software output -(Elmhurst, Stroma, etc.) exactly for RdSAP 10 input certs. The domain -concept is **Calculated SAP10 Performance** — see -`docs/adr/0009-deterministic-sap-calculator.md`. Progress is tracked in -`docs/sap-spec/SPEC_COVERAGE.md`. - -The workflow is strict TDD: **one failing test → minimal implementation → -commit**. Each commit is one slice. - ---- - -## Current state - -### §1 Dimensions — DONE -All 6 Elmhurst fixtures pass exactly (`test_section_1_matches_elmhurst_worksheet`). - -### §2 Ventilation — DONE -All 6 Elmhurst fixtures pass exactly (`test_section_2_matches_elmhurst_worksheet`). - -### §3 Heat transmission — PARTIALLY DONE - -What passes today: -- **Internal invariants** (all 6 fixtures): `(33) = Σ per-element`, - `(37) = (33) + (36)`. -- **Exact LINE_31 + LINE_36** (non-RR fixtures 000474 and 000490 only): - `test_section_3_non_rr_line_31_and_36_match_elmhurst_worksheet`. - -What does NOT yet pass: -- **Exact LINE_33** (fabric heat loss) for any fixture. This is the - remaining §3 close task (see below). -- **RR sub-areas** (fixtures 000487, 000480, 000477, 000516): gable/ - slope/stud-wall/flat-ceiling areas are not in `SapRoomInRoof`; these - fixtures are **formally deferred** — see gap notes in - `test_section_3_partial_match_against_elmhurst_worksheet`. - ---- - -## Task A — Close LINE_33 for non-RR fixtures (investigation slice) - -**Goal:** assert exact LINE_33 and LINE_37 for 000474 and 000490. - -### The diagnostic gap - -Running `heat_transmission_from_cert(epc, window_total_area_m2=0, door_count=actual)` on -000474 gives `fabric = 193.83 W/K`. The Elmhurst `LINE_33 = 209.11 W/K`. -The gap is +15.28 W/K — and it cannot be explained by window area alone, -because `u_wall (1.5) > u_window_eff (1.33)`, so adding windows would -*decrease* fabric heat loss, not increase it. - -The gap is therefore in one or more of the other elements. Most likely -culprits, in priority order: - -1. **Floor construction missing from fixture.** - `SapFloorDimension.floor_construction` is `None` in all Elmhurst - fixture files (field not set). Our `u_floor` fallback may not match - the Elmhurst value. The 000490 fixture comment records the expected - U-values explicitly: *"suspended timber ground floor on main (U=0.71), - exposed timber floor on Extension 1 (U=1.20)"*. Set the correct - `floor_construction` and `floor_insulation` codes on each - `SapFloorDimension` and see if the gap closes. - -2. **Roof construction / insulation thickness missing from fixture.** - Similarly, `roof_insulation_thickness` may not be set on the building - parts. The Elmhurst cert will have a specific roof type and insulation - depth that drives a specific `u_roof`. - -3. **Wall insulation re-check.** All fixtures use `wall_insulation_type=4` - (`_WALL_INSULATION_NONE`), giving `u_wall = 1.5` for cavity age B. - Confirm this matches the actual Elmhurst worksheet row. - -### How to proceed - -1. Read the EPC API field encoding for `floor_construction` and - `floor_insulation` in `datatypes/epc/domain/epc_property_data.py` - and `packages/domain/src/domain/ml/rdsap_uvalues.py` (the `u_floor` - function + its construction constants). -2. Look up the actual floor type for 000474 and 000490 from the PDF - (ask the user — PDFs were supplied manually; not stored in repo). -3. Set `floor_construction` + `floor_insulation` + `floor_insulation_thickness` - on the `SapFloorDimension` objects in the fixture files. -4. Re-run the debug calc (`r0.fabric` with `window_area=0`) and check - whether the gap collapses. -5. Once floor/roof are resolved, back-calculate window area: - `A_w = (LINE_33 - r0.fabric) / (window_u_eff - u_wall)`. - If the gap is now ≤ the window contribution, this formula should give - a physically plausible positive area (5–15 m² for a 2-storey terrace). -6. Add `WINDOW_TOTAL_AREA_M2: float` and `WINDOW_AVG_U_VALUE: float = 1.4` - constants to each non-RR fixture file. -7. Write a new parametrised test asserting exact LINE_33 and LINE_37 for - 000474 and 000490. Commit as one slice. - ---- - -## Task B — Table 11 Secondary Heating (highest-MAE-impact gap) - -Per `SPEC_COVERAGE.md`, this is the **next priority after §3**. - -Most boiler-main certs allocate ~10 % of space heating to a secondary -system (electric room heater or similar). We currently model 0 %. This -causes a systematic bias on the large majority of boiler certs. - -**SAP 10.2 Table 11** gives the secondary fraction keyed on main-heating -type. **RdSAP 10 Appendix A** identifies the heating type from cert codes. - -Starting point: `packages/domain/src/domain/sap/calculator.py` (entry -point) and `packages/domain/src/domain/sap/rdsap/cert_to_inputs.py` -(cert→inputs adapter). The `SapInputs` struct carries `main_heating_*` -fields — see how space heating demand is calculated and where a secondary -fraction would hook in. - ---- - -## Key files to read - -| File | Why | -|---|---| -| `packages/domain/src/domain/sap/worksheet/heat_transmission.py` | §3 implementation — `heat_transmission_from_cert` | -| `packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py` | all §3 tests including the partial Elmhurst conformance test | -| `packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py` | non-RR fixture to close | -| `packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py` | non-RR fixture to close | -| `packages/domain/src/domain/ml/rdsap_uvalues.py` | all U-value lookups — `u_floor`, `u_wall`, `u_roof` | -| `docs/sap-spec/SPEC_COVERAGE.md` | overall progress tracker | -| `docs/adr/0009-deterministic-sap-calculator.md` | scope + architectural decisions | - -Spec PDFs are at `docs/sap-spec/` — SAP 10.2 (March 2025), SAP 10.3 -(Jan 2026), RdSAP 10 (June 2025). - -The canonical reference Excel worksheet is at the repo root: -`2026-05-19-17-18 RdSap10Worksheet.xlsx`. A loader for it is at -`packages/domain/src/domain/sap/worksheet/tests/_xlsx_loader.py`. - ---- - -## Test suite - -``` -python -m pytest packages/domain/src/domain/sap/worksheet/tests/ -q -# Should show 122 passed -``` diff --git a/docs/sap-spec/SPEC_COVERAGE.md b/docs/sap-spec/SPEC_COVERAGE.md index 873bed11..94fde8f4 100644 --- a/docs/sap-spec/SPEC_COVERAGE.md +++ b/docs/sap-spec/SPEC_COVERAGE.md @@ -2,16 +2,18 @@ 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-18 after S-B19. +Updated 2026-05-20 after §3 close (slices `344a9c9d`…`cf244762`). + +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`. ## Sections §§1–13 (the SAP worksheet) -| § | Topic | Module | Status | Notes / gaps | -|---|---|---|---|---| -| 1 | Dimensions | `worksheet/dimensions.py` | **Full** | Porches, conservatories, RIR deferred per ADR-0009 | -| 2 | 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 | Heat transmission | `worksheet/heat_transmission.py` | Partial | DwellingExposure for flats ✓, but uses global y-factor (Table R2 per-junction deferred); no roof-light separate U-value | -| 4 | Hot water + Appendix J | uses `domain.ml.demand.predicted_hot_water_kwh` | Partial | Instantaneous-system flag ✓; no shower/bath count adjustments, no FGHRS/WWHRS, no PV-diverter | +| § | xlsx rows | Topic | Module | Status | Notes / gaps | +|---|---|---|---|---|---| +| 1 | 1–120 (approx) | Dimensions | `worksheet/dimensions.py` | **Full** | Porches, conservatories, RIR deferred per ADR-0009 | +| 2 | 121–206 (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 | 121–207 | 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 | 207–304 | Hot water + Appendix J | uses `domain.ml.demand.predicted_hot_water_kwh` | Partial (legacy) | **Worksheet-driven rewrite in progress** — see slice plan below. Instantaneous-system flag ✓; no shower/bath count adjustments, no FGHRS/WWHRS, no PV-diverter | | 5 | Internal gains + Appendix L | `worksheet/internal_gains.py` | Full | Default occupancy + Appendix L lighting fallback | | 6 | Solar gains + Tables 6b/6c/6d + Appendix U | `worksheet/solar_gains.py` | Partial | Per-orientation/pitch ✓; Tables 6b/6c lookups ✓; Z (overshading) hardcoded to 0.77 average; roof-lights treated as vertical | | 7 | Mean internal temperature | `worksheet/mean_internal_temperature.py` | Partial | Living area fraction from Table 27 ✓ (per S-A7b); control_type from main_heating_control code ✓ (S-B5); control_temperature_adjustment_c always 0 | @@ -58,3 +60,26 @@ Updated 2026-05-18 after S-B19. 6. **Per-junction thermal bridging (Table R2)** — only relevant when assessor lodged junction-count data, otherwise global y is the spec answer for RdSAP-driven assessments. Status now: 100-cert MAE 4.49, 300-cert MAE 5.45, bias near zero (±0.2). Worksheet-driven phase begins with **Secondary heating Table 11** as the next slice. + +## §4 — current focus (xlsx rows 207–304) + +Line refs to implement in order (one TDD slice each): + +| Line ref | Description | xlsx row | +|---|---|---| +| (42) | Assumed occupancy N from Appendix J formula | 209 | +| (42a)m | Hot water — mixer showers, monthly | 215 | +| (42b)m | Hot water — baths, monthly | 218 | +| (42c)m | Hot water — other uses, monthly | 221 | +| (43) | Annual average hot water (litres/day) | 223 | +| (44)m | Daily hot water usage, monthly | 226 | +| (45)m | Energy content of hot water, monthly | 229 | +| (46)m | Distribution loss = 0.15 × (45)m | 236 | +| (47)–(56) | Storage volume + water storage / HIU loss path | 238–263 | +| (57) | Dedicated solar storage adjustment | (after 263) | +| (58)–(61) | Primary loss + combi loss | — | +| (62)m | Total monthly water heat requirement | — | +| (63a)–(63d) | WWHRS / PV-diverter / Solar / FGHRS reductions | — | +| (64)m | Output from water heater | — | +| (64a)m | Electric-shower energy | — | +| (65)m | Heat gains from water heating | — |