From af477678c248b5631343f8ae17eaea394123201b Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 3 Jun 2026 10:14:17 +0000 Subject: [PATCH] =?UTF-8?q?docs:=20handover=20post=20S0380.195=20=E2=80=94?= =?UTF-8?q?=206035=20OPEN,=20API-mapper=20roof/RR=20over-count=20lead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Retracts the premature "6035 = lodged divergence" claim (S0380.195 commit msg + fixture docstring). The golden residual SAP -2 / PE +19.16 / CO2 +0.42t is REAL and exceeds the fallback bar. Section-level diff of 6035 (API) vs sim case 4 (site-notes, pins @1e-4) localised it to a cross-mapper parity break: roof W/K 78.33 (site-notes) vs 130.73 (API), a +52 over-count from the API RR scalar path + roof_construction=4. Next agent starts there. Co-Authored-By: Claude Opus 4.8 --- .../docs/HANDOVER_POST_S0380_195.md | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 domain/sap10_calculator/docs/HANDOVER_POST_S0380_195.md diff --git a/domain/sap10_calculator/docs/HANDOVER_POST_S0380_195.md b/domain/sap10_calculator/docs/HANDOVER_POST_S0380_195.md new file mode 100644 index 00000000..a5f6945c --- /dev/null +++ b/domain/sap10_calculator/docs/HANDOVER_POST_S0380_195.md @@ -0,0 +1,147 @@ +# Handover — post S0380.195 (gas-combi site-notes + RR/floor bugs; 6035 OPEN) + +Point-in-time note. Start from [`AGENT_GUIDE.md`](AGENT_GUIDE.md) for methodology, +accuracy bar, and pipeline — this records *what this session did* and *what is open*. + +- **Branch:** `feature/per-cert-mapper-validation` +- **HEAD:** `4a21717d` (S0380.195) +- **Baseline:** `2341 passed, 1 skipped, 0 failed`. Verify with the §4 suite command. + +--- + +## What this session shipped (S0380.190–195 + 1 extractor fix) + +| Slice | What | Spec | +|---|---|---| +| **.190** | Gas-combi site-notes `main_fuel_type` derivation. Newer Elmhurst export lodges §14.0 Fuel Type EMPTY + SAP code 104 → `MissingMainFuelType` blocked ALL gas-combi Summary certs. Derive carrier from §15.0 Water Heating Fuel Type for Table 4b gas-boiler codes 101–119 (NOT "104→mains gas" — Table 4b gas codes span mains gas/LPG/biogas; §15.0 disambiguates). `_elmhurst_gas_boiler_main_fuel`. | SAP 10.2 Table 4b p.168 | +| extractor fix | Windows-table header remnant ("value value Proofed Shutters") leaked into the FIRST window's `glazing_type` (layout `before_start=0` reaches the wrapped header). Trim prefix to the glazing-start word. | — | +| **.191** | Promoted sim case 1 (single-part gas combi) to e2e harness `001431`, 11 pins @1e-4. Resolved the handover's "+0.0007 SAP" as a display-rounded-ECF target artifact. | — | +| **.192** | **Simplified room-in-roof bug.** A Simplified RR (assessment "Simplified") lodges PLACEHOLDER slope/ceiling L×H (40 m ceiling height, 32 m slope). Spec derives one timber-framed remaining area `A_RR = 12.5√(A_floor/1.5) − Σgables`. The cascade already computes this (`has_roof_lodgement` gate in heat_transmission.py) but `_map_elmhurst_rir_surface` emitted the placeholder slope/ceiling → 1024+160 m² roof → **7.5× heat-loss explosion (SAP −14.6)**. Fix: drop roof-going surfaces for Simplified. API path (6035) already correct via scalar gable fields. | RdSAP 10 §3.9.1 p.21 | +| **.193** | **Suspended-floor (12) sealed rule.** Rule (a) "floor U<0.5 → sealed 0.1" applies only when a U-value is SUPPLIED; an as-built/default U falls to (b)→unsealed 0.2. Cascade fed the computed default U into (a) → wrongly sealed → ~450 kWh space-heat understatement. Fix: gate (a) on `floor_u_value_known`. | RdSAP 10 §5 p.29 | +| **.194** | Sim case 3 (8 windows, symmetric HLP) → e2e `001431_rr8`, 11 pins @1e-4. | — | +| **.195** | Sim case 4 (6035 floor geometry: Main ground HLP 15.99 + first 8.32) → e2e `001431_6035`, 11 pins @1e-4. | — | + +Net: 4 new Elmhurst-only e2e fixtures (cases 1–4 of cert 001431), all @1e-4. The +worksheet Summaries are mirrored into `backend/documents_parser/tests/fixtures/` +(`Summary_001431_gas_combi.pdf`, `_rr_ext`, `_rr8w`, `_6035`); source Summary + +P960 worksheet tracked under `sap worksheets/golden fixture debugging/simulated +case {1..4}/`. + +**The .195 commit message and the `_elmhurst_worksheet_001431_6035.py` docstring +claim 6035's +19 PE is "lodged divergence." THAT CLAIM IS RETRACTED — see below.** + +--- + +## OPEN (the priority) — golden cert 6035 residual is REAL, not divergence + +`tests/.../test_golden_fixtures.py` pins cert `6035-7729-2309-0879-2296`: +`actual_sap=70, expected_sap_resid=-2, expected_pe_resid=+19.16, +expected_co2_resid=+0.42 t`. **All three exceed the ±0.5 SAP / small-CO2 fallback +bar.** A −2 SAP is not rounding. 6035 was lodged **2025-11-11** under +RdSAP-Schema-21.0.1 / SAP 10.2 (software `5.02r0328`) — the SAME methodology we +target, so it is NOT a version artifact. + +### What we know +- **The cascade reproduces Elmhurst's WORKSHEET engine** for this archetype: sim + cases 1–4 (Main+Ext+RR+suspended-floor+gas-combi-104) all pin @1e-4 on all 11 + Block-1 line refs. +- **Case 4 ≈ 6035.** Identical: 2 BPs, age A, solid-brick walls (Main ins, Ext + as-built), RR floor 29.75, floor areas, **Main floors HLP 15.99/8.32**, doors, + heating (104/control 2106), 8 windows by **area + BP + 7/8 orientations**. + Remaining input diffs case4-vs-6035: + 1. the **3.82 m² window**: North in case 4, **South** in 6035 (only window diff); + 2. **lighting bulbs**: case 4 cascade lighting 262 vs 6035's **364** (6035 lodges + 9 low-energy + 2 incandescent; case 4's Summary lighting parsed as None); + 3. **meter type** "Dual" (case4) vs API **2** (6035); + 4. 6035 lodges `cylinder_size=1` (case 4 none) — appears immaterial (HW matches). +- **Controlled test:** flipping case 4's 3.82 window N→S raises SAP only **+0.25** + (68.19→68.44). Nowhere near +2. So orientation does NOT explain the gap. +- **The energy/demand model looks ~right per-end-use.** Cascade DEMAND + (postcode) costs ≈ 6035's lodged costs: heating £1278 vs lodged £1285, HW £225 + vs £217, lighting £103 vs £103. So the −2 SAP lives in the **RATING block** + (UK-avg): cascade rating cost 948.59 → ECF 2.31 → SAP 67.81; register implies + cost ~£886 / ECF 2.15 / SAP 70. **Plus the CO2 (+0.42 t) is unexplained.** +- Neither bug fixed this session touches 6035 (its RR uses the API scalar-field + path, already correct; its floor U=0.63 ≥ 0.5 was already "unsealed"). + +### The contradiction to resolve +Elmhurst-worksheet-for-case4-inputs = **68**, 6035-register = **70**, same +methodology, inputs nearly identical, and the known diffs explain only ~+0.25. +Either (a) 6035's register was produced from inputs materially different from the +golden JSON in a rating-relevant way we can't see, or (b) there's a real cascade +bug only 6035's exact combination triggers (the simulated cases didn't hit it). + +### ★ BREAKTHROUGH LEAD (end of session) — API-mapper roof/RR over-count +The user's hypothesis ("something missing from the API mapper") is CONFIRMED. +Diffing **6035 (API path) vs case 4 (site-notes path)** at the SECTION level +(`heat_transmission_section_from_cert`) — with near-identical fabric — exposes a +cross-mapper parity break that should not exist: + +| §3 line | case4 (site-notes) | 6035 (API) | Δ | +|---|---|---|---| +| **roof W/K** | **78.33** | **130.73** | **+52.39** | +| party W/K | 36.86 | 0.00 | −36.86 | +| (33) fabric heat loss | 290.72 | 304.66 | +13.94 | +| (31) total ext area | 231.02 | 242.74 | +11.72 | +| walls / floor / windows / doors | — | — | ≈0 | + +**The roof +52 W/K is the prime suspect for the whole 6035 residual** (52 W/K of +spurious heat loss ≈ the −2 SAP / +19 PE / +0.42 t CO2). Root cause is the RR/roof +representation feeding two DIFFERENT cascade paths: +- **case 4 (site-notes):** `sap_room_in_roof.detailed_surfaces=[gable_wall_external, + gable_wall]`, scalar gable lengths = None, `roof_construction=None` → cascade's + Detailed-loop residual path (`12.5√(A_floor/1.5) − Σwalls`) → roof 78.33. ✓ + (pins to case-4 worksheet @1e-4). +- **6035 (API):** `detailed_surfaces=None`, scalar `gable_1/2_length_m=4.65`, + **`roof_construction=4`** → cascade's SCALAR RR path (heat_transmission.py + ~363-460 + ~853-875) AND a separate `roof_construction=4` main-roof element → + roof 130.73. Likely DOUBLE-COUNTS the main roof over the full footprint with the + RR, or the scalar A_RR path over-states the area. + +Hand-check: for 6035 the correct roof ≈ RR remaining (12.5√(29.75/1.5) − 2×11.39 += 32.88 × 2.30 = 75.6) + main-loft residual (41.73−29.75=11.98 × 0.14 = 1.68) + +ext roof (7.21 × 0.14 = 1.01) ≈ **78.3** (matches case 4). The API path's 130.73 is +~52 too high. + +**START HERE:** instrument the API RR/roof path for 6035. Compare +`_api_build_room_in_roof` (mapper.py ~2713) output + `roof_construction=4` +handling vs the site-notes detailed_surfaces path. Find where the extra ~52 W/K +roof comes from (main-roof-area double count with RR, or scalar A_RR over-state). +Fix so the API path matches the site-notes path (cross-mapper parity), then re-pin +6035's golden residual (should collapse toward 0). The party=0 (party_wall_ +construction=3) is secondary — verify 3=solid U=0 is correct first. + +This is a CALCULATOR/MAPPER bug, not lodged divergence — the byte-exact-worksheet +plan below is now a fallback only. + +### Fallback — byte-exact 6035 worksheet ("simulated case 5") +Ask the user to generate case 5 = case 4 with EVERY remaining input matched to +6035: **3.82 m² window → South**, **lighting = 9 low-energy + 2 incandescent**, +**meter type matched**, **cylinder matched**. Then: +- If the worksheet SAP = **70** → real cascade bug. Diff cascade vs worksheet + line-by-line (start §6 solar gains (74)–(83) for the south window, §8 lighting + (232)/Appendix L, then §10a/§12 rating cost/ECF and §12/§13 CO2). +- If the worksheet SAP = **68** → the register's 70 is the anomaly (lodged from + different inputs); 6035 becomes a documented register-vs-worksheet divergence. + +Parallel angle worth a look NOW (no new worksheet needed): the **lighting energy** +(cascade 364 for 9 LE + 2 inc, TFA 128) — verify against SAP 10.2 Appendix L; and +the **CO2 (+0.42 t)** decomposition by carrier (the demand-cost match suggests the +energy is right, so a CO2-FACTOR or rating-block issue is implicated). + +--- + +## Carry-over (lower priority, from the prior handover) +- `transform.py:973` treats `wall_construction in (5,6)` as timber-frame for the + ventilation structural-ACH split, but 6 = system-built (masonry); only 5/7/8 are + timber/cob/park. Possible latent ventilation-ACH bug — verify before touching. +- Summary-path `main_fuel_type` for non-gas/non-104 boilers (only 101–119 + the + existing liquid/solid/electric/community branches are covered). + +## Process notes +- One slice = one commit, spec citation in the message, `Co-Authored-By: Claude + Opus 4.8` trailer. AAA tests, `abs(x-y) <= tol` (not `pytest.approx`). +- The 4 sim-case e2e fixtures pin Block 1 (UK-avg rating) via + `Sap10Calculator().calculate(epc)` — NOT the postcode demand block. +- Window ORIENTATION does NOT change the SAP rating much (+0.25 for 3.82 m²) — do + not over-attribute the 6035 gap to it.