docs: SPEC_COVERAGE §6 row flip to Full + slice progress table

§6 Solar gains: Partial → Full. Six Elmhurst fixtures conform end-to-end
on (83) total solar gains and (84) total gains to ≤5e-3 W on every month
(144 monthly assertions GREEN). Slice progress table records the chain
from tracer Z-solar lookup through legacy deletion.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-20 21:03:06 +00:00
parent a0ce45c98c
commit 34f4fa8bef

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-20 after §5 rebuild (slices `3ec56216``bf6a7e04`).
Updated 2026-05-20 after §6 rebuild (slices `da5909de``a0ce45c9`).
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`.
@ -15,7 +15,7 @@ The canonical SAP10.2 algorithm lives in [`2026-05-19-17-18 RdSap10Worksheet.xls
| 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. |
| 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` | Partial | Per-orientation/pitch ✓; Tables 6b/6c lookups ✓; Z (overshading) hardcoded to 0.77 average; roof-lights treated as vertical |
| 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` | 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 |
| 8 | Off-period temperature reduction | inline in `mean_internal_temperature.py` | Full | Table 9b implemented |
| 9 | Space heating | `worksheet/space_heating.py` | Partial | Single main system only — **no Table 11 secondary heating allocation** (10% fraction on most boilers — likely big MAE) |
@ -118,3 +118,29 @@ Status now: 100-cert MAE 4.49, 300-cert MAE 5.45, bias near zero (±0.2). Worksh
2. **Per-window `frame_material` / `glazing_type` strings** — current orchestrator uses cert numeric codes; needs a robust mapping for site-notes-sourced certs.
3. **Rooflight derivation from cert** — orchestrator accepts `rooflight_total_area_m2` but `cert_to_inputs` doesn't yet detect rooflights (defaults to 0). Needs the `SapWindow.window_location` enum that's TODO'd in the domain model.
4. **Column B reduced-gain forms** (L12a / L16) for new-build DPER/TPER calculations — deferred until we onboard a new-build cert.
## §6 — slice progress (xlsx rows 332371)
| Line ref | Description | Status | Commit |
|---|---|---|---|
| — | Table 6d Z-solar lookup (winter / heating column) | ✅ | `da5909de` |
| (74)..(81) | Per-orientation solar gain (N..NW) | ✅ | `4b83e702` |
| (82) | Roof windows — RdSAP10 Table 24 pitch 45° default, Z=1.0 | ✅ | `4b83e702` |
| (82a) | Rooflights — SAP10.2 §U3.2 horizontal, Z=1.0 | ✅ | `4b83e702` |
| (83) | Total solar gains 12-tuple | ✅ | `4b83e702` |
| — | `RoofWindowInput` + `RooflightInput` + `SolarGainsResult` | ✅ | `4b83e702` |
| — | `solar_gains_from_cert` orchestrator | ✅ | `4b83e702` |
| — | Manufacturer `window_transmission_details` cascade | ✅ | `d56fef4d` |
| — | 6-fixture ALL_FIXTURES conformance (83) + (84) ≤5e-3 W | ✅ | `377caea2` |
| — | `CalculatorInputs.solar_gains_monthly_w` + per-month lookup | ✅ | `376cdb6b` |
| — | `cert_to_inputs` swap legacy `_solar_gains_w` → orchestrator | ✅ | `cd2bd9ce` |
| — | Delete `_solar_gains_w` + `WindowInput` + `_window_inputs` | ✅ | `a0ce45c9` |
**Six Elmhurst fixtures conform end-to-end on §6 to ≤5e-3 W on every month of (83) total solar gains and (84) total gains** (the latter cross-checks §5 LINE_73 plus §6 LINE_83). 144 monthly assertions across 6 fixtures, all GREEN.
### Remaining §6 work
1. **Rooflight derivation from cert**`cert_to_inputs` passes `rooflights=()` because Elmhurst summaries lodge rooflights as `window_location = "External wall"`; needs the `SapWindow.window_location` enum work (also blocking §5 rooflight detection — common ticket).
2. **Roof window detection from cert** — same constraint as rooflights; orchestrator-side support is there (`RoofWindowInput` with pitch default), but the cert→inputs mapper has no signal to populate it.
3. **Multi-window-type per orientation** — orchestrator sums all windows of one orientation regardless of glazing type, matching the Elmhurst worksheet's per-orientation Σ. The xlsx repeats (74)..(82a) blocks per "window type" for diagnostic display; we collapse to per-orientation totals. Faithful per-type printout would need a richer result dataclass.
4. **Table 6c metal frame factor** — orchestrator ships 0.8 (spec); the deleted legacy lookup had 0.83 (silent bug). Frame-material strings outside `metal`/`aluminium`/`wood`/`pvc`/`upvc`/`composite` fall through to 0.7 default.