From 560c912c0b54677c5f34c470c24f826c141c9bf3 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 8 Jun 2026 12:43:02 +0000 Subject: [PATCH] docs: roof-8 lead closed as data-fidelity (not a bug) + description-vs-code audit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records the session-4 audit: walls/heating/controls clean; roof_construction=8 ("Pitched, insulated", no measured thickness) computing U=2.30 is CORRECT, not a bug — confirmed by user worksheet sim-case-29 (band C → Elmhurst SAP 55 ≡ our 56.75; lodged 80 is data-fidelity artifact). Lesson: "insulated (assumed)" = the age-band default insulation level, not "well insulated". DO NOT re-chase roof-8. Co-Authored-By: Claude Opus 4.8 --- docs/HANDOVER_API_PROFILING.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/docs/HANDOVER_API_PROFILING.md b/docs/HANDOVER_API_PROFILING.md index 9fd1527c..516abed2 100644 --- a/docs/HANDOVER_API_PROFILING.md +++ b/docs/HANDOVER_API_PROFILING.md @@ -65,6 +65,31 @@ profile-surfaced buckets below. `roof_codes=1` broad bucket is mean −0.15 (the −1.78 was top-floor-electric-flat outliers −29/−25). Remaining gains need per-cert worksheets (start code-3) or the unsupported-schema ticket. +## SESSION-4 AUDIT — description-vs-code cross-check (other element types) +After floor-3, audited every API field that carries BOTH an integer code AND an +independent `…[].description` (roofs, walls, floors, main_heating, controls), by joining +code↔description on **single-element certs** (the multi-element `[]` summary is lossy). +- **Walls / heating / controls: CLEAN** — codes map 1:1 to their description families; + residual error is per-cert scatter, not mis-mapping. +- **Roof `roof_construction=8`: investigated hard, NOT a bug — DO NOT re-chase.** It looked + like a huge lead (n=57, ~189 |err|, mean −2.43) because code-8 sloping ceilings described + "Pitched, insulated" with no numeric thickness compute U=2.30 (e.g. 7921-0052 roof_w 241 + W/K, SAP 56.75 vs lodged 80). **User worksheet (simulated case 29) settled it: at band C, + RdSAP/Elmhurst assumes UNINSULATED for an "insulated (assumed)" roof+wall with no measured + thickness → Elmhurst SAP 55, which MATCHES our 56.75.** The lodged 80 needed real insulation + the API record doesn't carry = data-fidelity artifact (meter-3 class). KEY LESSON (user): + **"insulated (assumed)" = the age-band DEFAULT insulation level, NOT "well insulated"** — at + old bands that default is ~uninsulated. Re-audit by band confirmed: old-band no-numeric = + artifacts (we ≡ Elmhurst); newer-band code-8 already gets correct insulated U (2031 band I + U≈0.18, 1436 band E 0.17, 0536 band B 0.09) — their under-rates are elsewhere; numeric- + thickness = accurate (9884 +0.06). So the force-uninsulated-at-pre-1950 rule is CORRECT. + A roof-8 "fix" would push us AWAY from Elmhurst's faithful 55 toward the unreproducible 80. +- **Roof `roof_construction=3`: latent mis-map (inert).** gov desc "(another dwelling above)" + (party roof) but we map to "Pitched, no access to loft"; masked by dwelling exposure + (mean −0.06). Correct for robustness only if touching the roof mapper; not worth chasing. +- **Worksheet-gen constraints (user, for future repros):** Elmhurst no longer lets you pick + build form for a flat; and a band-C repro defaults to uninsulated walls+roof. + ## KEY INSIGHT (load-bearing, from the user) **The gov EPC API JSON is the published OUTPUT of RdSAP software (Elmhurst), not its input.** So any API field Elmhurst doesn't expose as an *input* is register metadata the RdSAP10 method