From 9a483b871145883c2c64a7137c37fe042a96bd2d Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 4 Jun 2026 18:36:13 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20handover=20=E2=80=94=20fold=20in=20S038?= =?UTF-8?q?0.227-229=20+=20PV=20diverter=20(G4)=20as=20the=20case-19=20nex?= =?UTF-8?q?t=20slice?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- .../docs/HANDOVER_API_SAMPLE_ACCURACY.md | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/domain/sap10_calculator/docs/HANDOVER_API_SAMPLE_ACCURACY.md b/domain/sap10_calculator/docs/HANDOVER_API_SAMPLE_ACCURACY.md index afbc4b6f..2aa3ff68 100644 --- a/domain/sap10_calculator/docs/HANDOVER_API_SAMPLE_ACCURACY.md +++ b/domain/sap10_calculator/docs/HANDOVER_API_SAMPLE_ACCURACY.md @@ -4,7 +4,7 @@ Point-in-time note. Start from [`AGENT_GUIDE.md`](AGENT_GUIDE.md) for methodolog 1e-4 bar, the per-line debugging loop, the section helpers, and the suite command. - **Branch:** `feature/per-cert-mapper-validation` -- **HEAD:** `c236aa58` (S0380.226). Next slice: **S0380.227**. +- **HEAD:** `0f6b4023` (S0380.229). Next slice: **S0380.230**. - **Baseline (§4 suite):** `tests/domain/sap10_calculator/ backend/documents_parser/tests/` → green (2397 passed, 1 skipped). Pre-existing out-of-scope failures unchanged (stone-§5.6 in `domain/sap10_ml/tests/`; `test_from_rdsap_schema.py::...test_total_floor_area`). @@ -87,30 +87,48 @@ auto-charge, 7-hr off-peak tariff) + a **loose-jacket 210 L cylinder** + **WHS 9 boiler for water only) + **room-in-roof gables (Party + Exposed) + an alternative wall + exposed floor + electric secondary**. -**S0380.226 unblocked extraction** (the "Jacket" label was raising). Running the Summary path -through the cascade vs the worksheet (rating block) then exposes the cat-7 cluster bugs — our -**SAP cont 60.2 vs worksheet ~51.2 (+9, the cluster signature)**: +**S0380.226 unblocked extraction** (the "Jacket" label was raising). The worksheet has FOUR +blocks: **block 1 = rating** (UK-avg region 0; cost (255)=1816.58, SAP (258)=51, TF (53)=0.60, +(51)=0.0330), **block 2 = demand** (postcode; CO2 (272)=3125.85, PE (286)=30271.76), blocks 3/4 += the potential/improved variants. Pin the rating block for SAP/cost, the demand block for +PE/CO2. Worksheet header line 116 lodges **"Separate Time Control: No"** (NOT in the Summary §15 +PDF — only in the P960 header). -| line ref | ours | worksheet | gap / cause | +**Three slices shipped (S0380.227–229)** — closed the +9 cluster signature; SAP cont +60.2 → **50.33** (worksheet ~51.22): + +| slice | line ref | fix | SAP cont | |---|---|---|---| -| **cost (255)** | 1482.12 | **1816.58** | **−334 → the primary +9 SAP driver.** Likely the Economy-7 off-peak tariff cost split (SAP 10.2 Table 12a / §10c high-rate vs low-rate). START HERE. | -| Table 2b TF (53) | 0.54 | **0.60** | we apply the ×0.9 separately-timed multiplier, but the Summary lodges "Separate Time Control: No" → should be 0.60. Check `_table_2b_note_b_multiplier_applies` / the override's `separately_timed_dhw` for a WHS-911 + storage-heater dwelling. | -| HW fuel (219) | ~3642 | 3188.17 | +454 HW over. Tied to the TF bug + how WHS-911 routes storage vs combi loss (the WaterHeating result showed a spurious `combi_loss` and `solar_storage=0` via the section helper — verify against the FULL cascade, the section helper may not mirror it). | -| fabric (33) | 305.04 | 304.04 | +1.0 W/K — minor; gable / alternative-wall rounding. Low priority. | -| CO2 (272) | 3124.67 | 3125.85 | ≈ exact. | +| **S0380.227** | TF (53) 0.54→**0.60**; (59) h=3→**h=5** | dedicated DHW-only system (WHS 911) is NOT separately timed → no Table 2b ×0.9 (RdSAP 10 §10.5.1). `_separately_timed_dhw` gated on WHC ∈ {901,902,914}. Worksheet-pins S0380.224's loose-jacket (51)=0.0330/(53)=0.60/(55)=3.4531/(56-57)Jan=107.0456 at 1e-4. | 60.2→60.1 | +| **S0380.228** | cost (255) | electric SECONDARY on off-peak bills at Table 12a `OTHER_DIRECT_ACTING_ELECTRIC` (7-hr high-frac **1.00** = £0.1529), not the flat off-peak low (£0.0550). Worksheet (242): "1.00*15.29 + 0.00*5.50". THE primary cost driver (−340). | 60.1→**50.67** | +| **S0380.229** | (62) 2493.30→**3169.98** | dedicated water-heating boiler/circulator (WHC 911-931) feeds the cylinder via a primary loop → Table 3 row 1 primary loss applies (keyed off `water_heating_code`, since `_water_heating_main` returns the electric SPACE main). Restored the missing (59)=676.68 kWh/yr. | 50.67→50.33 | + +**The ONE remaining case-19 cause — the PV diverter (63b) — is S0380.230 (next).** Worksheet +header line 124 "Diverter = Yes"; Summary §19 "Diverter present: Yes". Per **SAP 10.2 Appendix +G4 (PDF p.72-73)** surplus PV is diverted to the cylinder immersion: +`S_PV,diverter,m = EPV,m × (1 − βm) × 0.8 × 0.9`, clamped to ≤ (62)m + (63a)m, entered as a +NEGATIVE (63b)m. (64)m = (62)m + (63a)m + (63b)m + … → (219)m = (64)m / eff. All four G4 +inclusion conditions are met (PV connected to dwelling; cylinder 210 L > (43)=74.24; no solar +HW; no battery). Worksheet (63b) annual ≈ −1097.67 kWh → (64) drops 3169.98 → 2072.31, (219) +4876.9 → 3188.17. It ALSO changes the PV β-split (export drops: worksheet dwelling 1280.39 / +exported 184.16 vs our 1496.20 / 1187.98 with no diverter). This is a 3-layer feature +(extractor `Diverter present` → mapper flag → calculator (63b) + β-split interaction) — +implement as one focused slice. Spec note p.5485: for the β calc, (219)m must EXCLUDE the +diverter saving. + +Smaller residuals after the diverter lands: main fuel (211) ours 20250.22 vs ws 19910.30 +(+340), secondary (215) 3573.57 vs 3513.58 (+60), fabric (33) +1.0 (gable/alt-wall). Current +demand block: CO2 (272) 3331.04 vs 3125.85, PE (286) 31653.23 vs 30271.76 — both will drop with +the diverter (less grid import). **Debug recipe** (reuse the `/tmp/case19*.py` throwaways or rebuild): ```python pages → ElmhurstSiteNotesExtractor(...).extract() → from_elmhurst_site_notes → cert_to_inputs / cert_to_demand_inputs → calculate_sap_from_inputs -# section helpers: water_heating_section_from_cert / heat_transmission_section_from_cert -# CI._cylinder_storage_loss_override(epc, main) returns (57)m directly — useful to bisect. +# CI._cylinder_storage_loss_override(epc, main) → (57)m; CI._primary_loss_override(epc, age) → (59)m +# CI._water_heating_worksheet_and_gains(epc=…, water_efficiency_pct=0.65, is_instantaneous=False, +# primary_age=, pcdb_record=None) → wh_result with (45)/(46)/(57)/(59)/(62)/(64) ``` -The worksheet's rating block is block 1 (UK-avg, region 0); the demand block (postcode) is -block 2. Pin the rating block for SAP/cost, the demand block for PE/CO2. - -S0380.224's loose-jacket magnitude can be **worksheet-pinned at 1e-4 here** once the TF bug is -fixed (worksheet (51)=0.0330, (52)=0.8298, (53)=0.6000, (55)=3.4531, (56)Jan=107.0456). ---