From f4a759ade38d23aafeb055f3671dd2808f9d7f89 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 1 Jun 2026 16:01:52 +0000 Subject: [PATCH] docs: handover post S0380.153..155 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Session landed three spec-clean slices closing four major residuals: - S0380.153 (Table 3 middle row for solid-fuel boilers): SF3 EXACT all 4 metrics (+0.30 → -0.0000). Found the rule that solid-fuel boilers don't ship with dual programmers per §9.2.4. - S0380.154 (§12.4.4 back-boiler summer-immersion): SF2 SAP+cost EXACT (+1.86 → -0.0000 SAP; -£42.84 → -£0.00 cost). Implemented HW fuel kWh split + monthly blend across cost / CO2 / PE / standing. - S0380.155 (Table 4a HP water-column dispatch): gshp closed ±0.02 SAP (+0.94 → -0.0178). HW kWh 841 → 1138 matches worksheet exactly. Σ |ΔSAP_c| 14.5 (session start of S0380.150) → 2.7 = 81% reduction across 6 slices, two sessions. Handover doc captures: - Per-line discipline (walk worksheet before forming hypothesis) - Elmhurst-vs-spec divergences to defer (lighting-PE +48.66 cluster uses Table 12 annual factor; spec Table 12d mandates monthly) - Ranked open fronts (electric 5 R=0.20 storage MIT, electric 2 warm-air HP HW, deferred lighting-PE cluster) Co-Authored-By: Claude Opus 4.7 --- .../docs/HANDOVER_POST_S0380_155.md | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) create mode 100644 domain/sap10_calculator/docs/HANDOVER_POST_S0380_155.md diff --git a/domain/sap10_calculator/docs/HANDOVER_POST_S0380_155.md b/domain/sap10_calculator/docs/HANDOVER_POST_S0380_155.md new file mode 100644 index 00000000..e06d7f9e --- /dev/null +++ b/domain/sap10_calculator/docs/HANDOVER_POST_S0380_155.md @@ -0,0 +1,276 @@ +# Handover — post Slices S0380.153..155 + +Branch: `feature/per-cert-mapper-validation`. **HEAD `152db1ae`**. +Predecessor: [`HANDOVER_POST_S0380_152.md`](HANDOVER_POST_S0380_152.md). + +## TL;DR + +Three slices landed. Each addressed a distinct spec rule the cascade +was missing, all surfaced through the same heating-systems corpus +(property 001431 × 41 heating-system variants). + +| Slice | Commit | Spec rule closed | +|---|---|---| +| S0380.153 | `e4bf4e70` | SAP 10.2 Table 3 (p.160) — "not separately timed" middle row for solid-fuel boilers (codes 151-161). DHW timer follows the appliance, not a separate programmer. | +| S0380.154 | `5e941b92` | SAP 10.2 §12.4.4 (p.36-37) — back-boiler summer-immersion HW split for codes 156, 158. Cascade now blends winter boiler + summer electric immersion across kWh/cost/CO2/PE/standing-charge fields. | +| S0380.155 | `152db1ae` | SAP 10.2 Table 4a (p.163-164) — heat-pump water column distinct from space column for 10 codes (211/213/215/216/217 + 521/523/525/526/527). Cascade was using space efficiency for HW on these codes. | + +Extended handover suite at HEAD: **899 pass, 0 fail.** Pyright +net-zero (43 → 43). + +## Disciplines reinforced this session + +1. **Per-line walk before spec hypothesis.** S0380.153 found via + dumping SF3's worksheet (59)m row — it showed winter h=5 / summer + h=3 (= "not separately timed"), not the h=3 year-round the cascade + was using. The handover narrative said "SF2 separately-timed-DHW + gate" but the per-line walk revealed the rule applies to ALL + solid-fuel boilers (codes 151-161), not just back-boiler combos. + +2. **Bigger slice OK when one spec rule has multiple wire points.** + S0380.154 (§12.4.4) touched HW kWh + cost rate + CO2 factor + PE + factor + standing charges + primary-loss override — five distinct + plumbing points. Doing it as one coherent slice (vs splitting into + "fix kWh first, then fix cost") kept the residual pin monotonic. + +3. **Spec correctness > pin stability for Elmhurst-vs-spec gaps.** + The lighting-PE +48.66 cluster (5 variants with identical offset + from off-peak HW immersion) was deferred because Elmhurst uses + Table 12 ANNUAL factor (1.501 PE / 0.136 CO2) for off-peak HW + while spec Table 12d/12e header mandates MONTHLY factors. The + cascade follows spec; the cohort residual stays. + +## Current residual state at HEAD `152db1ae` + +### Cascade-OK tier (25 variants on pin grid) + +Sorted by |ΔSAP_c|: + +| Variant | ΔSAP_c | Δcost | ΔPE | Notes | +|---|---:|---:|---:|---| +| oil 1 | **-0.0000** | **-0.00** | **+0.00** | EXACT | +| oil pcdb 1/2 | **+0.0000** | **+0.00** | **+0.00** | EXACT | +| oil pcdb 3 | **+0.0000** | **+0.00** | **-0.00** | EXACT | +| electric 1 | **-0.0000** | **-0.00** | +48.66 | SAP exact, PE Elmhurst quirk | +| solid fuel 5 | **+0.0000** | **+0.00** | +48.66 | SAP exact, same quirk | +| solid fuel 6 | **+0.0000** | **+0.00** | +48.66 | SAP exact, same quirk | +| solid fuel 7 | **-0.0000** | **+0.00** | +48.66 | SAP exact, same quirk | +| solid fuel 8 | **-0.0000** | **+0.00** | +48.66 | SAP exact, same quirk | +| **solid fuel 2** | **-0.0000** | **-0.00** | -1027.51 | **closed by .154** (SAP+cost EXACT; CO2/PE Elmhurst blend artifact) | +| **solid fuel 3** | **-0.0000** | **-0.00** | -0.00 | **closed by .153** (4-metric EXACT) | +| pcdb 1 | -0.0108 | +£0.24 | +5.70 | basically exact | +| **gshp** | **-0.0178** | **+£0.41** | +33.52 | **closed by .155** (HW kWh 841→1138 matches worksheet) | +| ashp | -0.024 | +£0.55 | +36.34 | basically exact | +| solid fuel 4 | +0.085 | -£1.96 | -5.78 | close | +| solid fuel 11 | +0.0912 | -£2.10 | -0.74 | close | +| electric 8 | +0.0941 | -£2.17 | +6.58 | close | +| electric 7 | +0.1017 | -£2.34 | +3.10 | close | +| electric 6 | +0.1081 | -£2.49 | +0.16 | close | +| solid fuel 9 | +0.1072 | -£2.47 | -5.07 | close | +| solid fuel 10 | +0.1134 | -£2.61 | -13.91 | close | +| electric 9 | +0.1199 | -£2.76 | -4.51 | close | +| electric 3 | +0.1215 | -£2.80 | -5.99 | close | +| **electric 2** | **-0.4584** | **+£10.56** | **+443.13** | warm-air HP code 524 — open Cluster C | +| **electric 5** | **-1.1759** | **+£27.09** | **+438.03** | storage code 402 R=0.20 — open | + +Σ |ΔSAP_c| across 25 variants ≈ **2.7 SAP points** (was 14.5 at session start, +~6.4 after .150-.152, now ~2.7 = 81% reduction across 6 slices over +two sessions). + +### Blocked tier (16 variants — `MissingMainFuelType`) + +Unchanged. Community heating × 5, electric storage 11-14, no system, +oil 2-6, pcdb 3. + +## Open fronts ranked by leverage + +### 1. **electric 5 — SAP -1.18 / cost +£27 / PE +438** (largest open) + +Storage heater code 402 (R=0.20, slimline). REGRESSED by S0380.145 + +S0380.151 — pre-S0380.145 was net-zero from offsetting bugs. + +Per-line probe at session-end: + - Cascade adjusted MIT[Jan] = 19.10 vs worksheet (93) = 18.61 + (cascade +0.49 K higher) + - Cascade base MIT[Jan] = 18.70 vs worksheet (92) = 18.21 + (cascade +0.49 K higher — same diff) + - Cascade `control_temperature_adjustment_c` = +0.4 K (Table 4e + code 2402 — correct) + - Per-zone components diverge: cascade T_living = 19.85 vs ws 19.65; + T_h2 = 18.59 vs ws 19.12; T_elsewhere = 17.27 vs ws 17.59. + +The diverging components suggest §9 Table 9a/9b off-period reduction +formula differs in Elmhurst for R=0.20 storage heaters. Cascade's +formula: +``` + T_sc = (1-R)(T_h - 2) + R(T_e + η·G/H) + if t_off > t_c: u = (T_h - T_sc)(t_off - 0.5·t_c) / 24 +``` +matches spec verbatim. But the per-zone numbers (T_h2 cascade 18.59 +vs ws 19.12) suggest a HEAT LOSS PARAMETER or HLP-formula divergence +upstream of the off-period reduction. + +This needs careful spec analysis of Table 9c steps for low-R systems +— may take 1-2 slices. NOT a quick win. + +### 2. **electric 2 — SAP -0.46 / cost +£10.56 / PE +443** + +Warm-air ASHP code 524 (Space = Water = 170, so S0380.155 fix +doesn't apply). Cascade HW kWh OVER worksheet by 465 kWh (+19%) — +opposite direction from gshp. Distinct spec rule. Probably HW +efficiency cascade for warm-air HPs (Appendix N3 has separate +treatment from Cat 4 hydronic HPs). + +### 3. **Lighting-only PE +48.66 cohort cluster (5 variants)** — **DEFERRED** + +electric 1, solid fuel 5/6/7/8. All have identical PE +48.66 / CO2 ++11.94 offset from off-peak HW immersion. Worksheet uses Table 12 +ANNUAL factor (1.501 / 0.136) on the "low-rate cost" line; cascade +uses Table 12d/12e MONTHLY cascade per spec header. Cascade is +spec-correct. Elmhurst applies an undocumented exception for +off-peak HW immersion. Cannot close without violating spec. + +### 4. **electric 3 / 6 / 7 / 8 / 9 + solid fuel 9-11 — ΔSAP ±0.09-0.12** + +Residual cluster — likely a shared shave-the-residual fix. Probably +the same Elmhurst-vs-spec PE blend artifact as #3 but for the +secondary-heating fraction or similar. Lowest leverage. + +### 5. **gshp ΔSAP -0.018 / ΔPE +34** — landed in S0380.155 + +Sub-tolerance close but not 1e-4. Same Elmhurst-vs-spec PE blend +artifact as #3 (HW from HP is on standard tariff, not off-peak, so +NOT the same off-peak-immersion path — but same monthly-vs-annual +factor pattern). Defer until the cluster fix lands. + +## Slice history (this session) + +| Slice | HEAD | Scope | +|---|---|---| +| S0380.153 | `e4bf4e70` | SAP 10.2 Table 3 (PDF p.160) middle row "Cylinder thermostat, water heating NOT separately timed" applies to solid-fuel boiler systems. Per §9.2.4 these are "independent solid fuel boilers, open fires with a back boiler and room heaters with a boiler" — the appliance is the timer. New `_TABLE_4A_SOLID_FUEL_BOILER_CODES` frozenset + branch in `_separately_timed_dhw`. SF3 (code 160 + WHC=901): worksheet (59)m winter 64.58 / summer 41.92 matches cascade. ΔSAP +0.30 → -0.0000 EXACT all 4 metrics. SF2 narrows +2.06 → +1.86 (remaining is the §12.4.4 immersion rule). | +| S0380.154 | `5e941b92` | SAP 10.2 §12.4.4 (PDF p.36-37) back-boiler summer-immersion HW split. For Table 4a codes 156 + 158 (back-boiler combos) + WHC ∈ {901, 902, 914} + cylinder, HW splits: winter (Oct-May) at boiler eff + summer (Jun-Sep) at 100% electric immersion. New `_section_12_4_4_summer_immersion_applies(epc, main)` predicate + `_section_12_4_4_hw_blend(...)` returning 5-tuple (annual_hw_fuel_kwh, blended_cost, blended_co2, blended_pe, extra_standing). `_primary_loss_override` zeros (59)m Jun-Sep. Orchestrator wires 4 fields + standing once. SF2 closures: ΔSAP +1.86 → -0.0000 EXACT, Δcost -£42.84 → -£0.00 EXACT; CO2/PE residuals -93/-1027 are Elmhurst summer CO2/PE blend artifacts vs Table 12d/12e. | +| S0380.155 | `152db1ae` | SAP 10.2 Table 4a (PDF p.163-164) heat-pump rows split efficiency into Space and Water columns. Codes 211/213 (Cat 4 GSHP/WSHP ≤35°C: SH 230 / DHW 170), 215/216/217 (Cat 4 gas-fired HP ≤35°C: SH 120-110 / DHW 84-77), and Cat 5 warm-air equivalents 521/523/525/526/527. New `_TABLE_4A_HEAT_PUMP_WATER_EFFICIENCY` 10-code dict consulted in `_water_efficiency_with_category_inherit` before `seasonal_efficiency` fallback. Codes where Space == Water (214/221/223/224/524) unchanged. gshp (code 211) HW kWh 841 → 1138.45 (matches worksheet 1138.46). ΔSAP +0.94 → -0.0178. No regressions on 40 other variants. | + +## Standard slice workflow (unchanged) + +1. Read spec page + identify rule +2. Probe one cluster variant; verify diagnosis via monkey-patch / direct walk +3. Write failing AAA test (literal `# Arrange / # Act / # Assert`) +4. Implement helper / dispatch entry / mapper extension +5. Re-pin affected variants (DO NOT widen tolerance) +6. Run extended handover suite (command below) +7. Pyright net-zero check (`git stash` → pyright → `git stash pop` → pyright) +8. Commit with spec citation + `Co-Authored-By: Claude Opus 4.7 ` +9. Update `project-heating-systems-corpus` + `MEMORY.md` index + +## Test baseline at HEAD `152db1ae` + +```bash +PYTHONPATH=/workspaces/model python -m pytest \ + backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \ + backend/documents_parser/tests/test_heating_systems_corpus.py \ + backend/documents_parser/tests/test_elmhurst_extractor.py \ + backend/documents_parser/tests/test_elmhurst_end_to_end.py \ + domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \ + domain/sap10_calculator/worksheet/tests/test_heat_transmission.py \ + domain/sap10_calculator/worksheet/tests/test_internal_gains.py \ + domain/sap10_calculator/worksheet/tests/test_solar_gains.py \ + domain/sap10_calculator/worksheet/tests/test_dimensions.py \ + domain/sap10_calculator/worksheet/tests/test_rating.py \ + domain/sap10_calculator/worksheet/tests/test_ventilation.py \ + domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py \ + domain/sap10_calculator/worksheet/tests/test_mev.py \ + domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py \ + domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \ + domain/sap10_calculator/tests/test_pcdb_table_322_lookup.py \ + domain/sap10_calculator/tests/test_pcdb_table_329_lookup.py \ + domain/sap10_calculator/tests/test_table_12a.py \ + --no-cov -q +``` + +Expected: **899 pass, 0 fail.** + +## Memories to load (in order) + +``` +project-heating-systems-corpus # HEAD 152db1ae +feedback-sap-10-2-only-never-10-3 # CRITICAL — never reference SAP 10.3 +feedback-software-no-special-handling # CRITICAL — apply spec uniformly +feedback-spec-floor-skepticism # CUTS BOTH WAYS — skeptical of your OWN audit narrative +feedback-worksheet-not-api-reference +feedback-spec-citation-in-commits +feedback-verify-handover-claims +feedback-zero-error-strict # TARGET: ΔSAP_c < 1e-4 vs worksheet +feedback-commit-per-slice +feedback-aaa-test-convention +feedback-e2e-validation-philosophy +feedback-abs-diff-over-pytest-approx +feedback-golden-residuals-near-zero +feedback-one-e-minus-4-across-the-board +reference-unmapped-sap-code +reference-unmapped-api-code +project-oil-price-spec-divergence +``` + +## What NOT to do + +- **Don't reference SAP 10.3** — track 10.2 deliberately +- **Don't widen pin tolerances** — re-pin smaller or find the spec gap +- **Don't add empirical gates** to keep cohort pins stable when a + spec rule clearly applies +- **Don't re-investigate Slices .91..155** — all settled +- **Don't add new helpers to `domain/sap10_ml/`** — on deprecation + path; `domain/sap10_calculator/tables/` is the canonical home +- **Don't treat ΔSAP=0.07 as "closed"** — target is <1e-4 vs worksheet +- **Don't try to close the lighting-PE +48.66 cluster** — it's an + Elmhurst-vs-spec quirk (Elmhurst uses Table 12 annual factor for + off-peak HW immersion while spec Table 12d/12e header mandates + monthly factors). Closing it would violate spec. +- **Don't form a spec hypothesis without per-line data** — walk the + worksheet line-by-line for the failing variant first, then look up + the spec rule. Headline residuals tell you a gap exists; only the + per-line walk tells you which section of the spec it lives in. + +## Spec source quick-reference + +All under `domain/sap10_calculator/docs/specs/`: + +- **SAP 10.2 full spec**: `sap-10-2-full-specification-2025-03-14.pdf` + - **§4** (p.135-137) — water heating worksheet (45..65) + - **§9.2.4** (p.27) — Solid fuel boiler systems (the appliance is + the timer; Table 3 not-separately-timed row applies). **Slice .153.** + - **§9.4.11** (p.30) — Boiler interlock: -5pp to BOTH SH and DHW + - **§9.4.19** (p.34-35) — Storage heater controls + - **§12** (p.45) — Electricity tariff types + - **§12.4.4** (p.36-37) — Solid fuel systems; back-boiler combos + use electric immersion in summer. **Slice .154.** + - **§A.2.2** (~p.189) — Forced-secondary set + - **Appendix D §D2.1 (2)** (p.57) — Eq D1 monthly water eff cascade + - **Appendix F2** (p.63) — 18-hour CPSU: high rate for all other uses + - **Appendix N3** (p.107-109) — Heat pump DHW efficiency cascade + - **Table 3** (p.160) — Primary circuit loss; zero-loss list + + middle row "not separately timed" h=5/h=3. **Slices .152 / .153.** + - **Table 4a** (p.163-170) — heating systems incl. **separate + Space + Water columns for HP rows**. **Slice .155.** + - **Table 4b** (p.168) — gas/liquid boilers seasonal efficiency + - **Table 4e** (p.171-173) — heating system controls + temperature + adjustment column. Group 4 codes 2401/2402/2403 = electric + storage controls (+0.7/+0.4/+0.4 K). + - **Table 4f** (p.174) — pumps + fans + - **Table 9a/9b** (p.183) — utilisation factor + off-period reduction + - **Table 9c** (p.184) — MIT cascade (step 8 = Table 4e adj wired) + - **Table 11** (p.188) — secondary heating fraction + - **Table 12** (p.191) — SAP rating fuel prices + standing charges + - **Table 12a** (p.191) — high/low-rate fraction by system × tariff + - **Table 12d** (p.195) — monthly variation in CO2 factors for + electricity (spec mandates use INSTEAD OF Table 12 annual) + - **Table 12e** (p.196) — monthly variation in PE factors + - **Table 13** (p.197) — high-rate fraction for electric DHW +- **RdSAP 10 spec**: `RdSAP 10 Specification 10-06-2025.pdf` + - **§4.1 Table 5** (p.28) — Ventilation parameters incl. + extract fans age-band default + - **§5** (p.29) — Floor infiltration spec rule + - **§10.11 Table 29** (p.56) — Heating/HW parameters; inaccessible cylinder + - **§19 Table 32** (p.95) — RdSAP10 fuel prices / CO2 / PE + +## Good luck.