Delete HANDOVER_FRESH_REVIEW (22-slice, MAE-5.34 era) and HANDOVER_SYSTEMATIC_REVIEW (pre-Elmhurst-conformance). Both described a state the Elmhurst worksheet work has since superseded. Add HANDOVER_S3_CLOSE.md with: - Accurate §3 status: §1/§2 fully done; LINE_31/LINE_36 exact for non-RR fixtures; LINE_33 gap diagnosed as missing floor_construction codes (not a window-area problem as previously assumed) - Concrete investigation steps to close LINE_33 for 000474 + 000490 - Table 11 Secondary Heating framed as next slice after §3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.3 KiB
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 intest_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:
-
Floor construction missing from fixture.
SapFloorDimension.floor_constructionisNonein all Elmhurst fixture files (field not set). Ouru_floorfallback 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 correctfloor_constructionandfloor_insulationcodes on eachSapFloorDimensionand see if the gap closes. -
Roof construction / insulation thickness missing from fixture. Similarly,
roof_insulation_thicknessmay not be set on the building parts. The Elmhurst cert will have a specific roof type and insulation depth that drives a specificu_roof. -
Wall insulation re-check. All fixtures use
wall_insulation_type=4(_WALL_INSULATION_NONE), givingu_wall = 1.5for cavity age B. Confirm this matches the actual Elmhurst worksheet row.
How to proceed
- Read the EPC API field encoding for
floor_constructionandfloor_insulationindatatypes/epc/domain/epc_property_data.pyandpackages/domain/src/domain/ml/rdsap_uvalues.py(theu_floorfunction + its construction constants). - Look up the actual floor type for 000474 and 000490 from the PDF (ask the user — PDFs were supplied manually; not stored in repo).
- Set
floor_construction+floor_insulation+floor_insulation_thicknesson theSapFloorDimensionobjects in the fixture files. - Re-run the debug calc (
r0.fabricwithwindow_area=0) and check whether the gap collapses. - 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). - Add
WINDOW_TOTAL_AREA_M2: floatandWINDOW_AVG_U_VALUE: float = 1.4constants to each non-RR fixture file. - 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