docs: mark Thread 3 (cert 0390) CLOSED by S0380.210

Update the mapper-bugs handover: Thread 3 closed via the cavity
"partial insulation (assumed)" → "Cavity as built" routing fix; record
the latent open question about the unvalidated "insulated (assumed)" →
filled-cavity test (slice S-B25). Bump HEAD/baseline/next-slice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-03 21:58:37 +00:00
parent c75ef6417f
commit 0add6b6a59

View file

@ -6,9 +6,11 @@ state after closing the 0240 investigation and fixing the first of several
API-mapper/cascade bugs the audit surfaced.
- **Branch:** `feature/per-cert-mapper-validation`
- **HEAD:** `844fc22f` (S0380.209). Confirm with `git rev-parse HEAD`.
- **Baseline:** `2383 passed, 1 skipped, 0 failed` (AGENT_GUIDE §4 suite command).
- **Next slice number:** **S0380.210**.
- **HEAD:** `c75ef641` (S0380.210). Confirm with `git rev-parse HEAD`.
- **Baseline:** `2384 passed, 1 skipped, 0 failed` (AGENT_GUIDE §4 suite command).
- **Next slice number:** **S0380.211**.
- **Open:** Thread 1 (roof, needs case 11) + Thread 2 (community 9390, needs 9390 ws).
Thread 3 (0390) **CLOSED** below.
---
@ -18,6 +20,7 @@ API-mapper/cascade bugs the audit surfaced.
|---|---|
| **S0380.208** | Promoted **simulated case 7** (combi swap of case 6) to an e2e fixture. PROVED the condensing-oil-combi (SAP code 130, no cylinder, combi instantaneous DHW, Eq D1, Table 3a keep-hot) path is **exact at 1e-4** with zero calculator changes → exonerated the heating as the source of 0240's residual. |
| **S0380.209** | Fixed the **API-path wall U** "as built, insulated (assumed)" bug — routes to the as-built age-band row, not the 50 mm retrofit bucket. New `_described_as_retrofit_insulated` in `heat_transmission.py`. Worksheet-validated by case 9 (sandstone J → 0.35) + case 10 (solid brick J → 0.35). Re-pinned 0240 PE +1.8687 → +5.5044, CO2 +0.0907 → +0.2757 (SAP integer 72 unchanged). |
| **S0380.210** | **CLOSED cert 0390** (Thread 3). Cavity wall "as built, **partial** insulation (assumed)" (type 4) was mis-routed to the Table 6 "Filled cavity" row (band F 0.40) → should be "Cavity as built" (band F 1.0). New `_cavity_described_as_filled` in `rdsap_uvalues.py` excludes "partial insulation" from the filled trigger (keeps "insulated (assumed)" → filled). SAP +7 → +0, PE 27.97 → +0.53, CO2 2.71 → 0.12. Mirrors S0380.209 on the cavity path. |
Both also carry a memory: [[project_case7_combi_exonerated]], [[project_as_built_insulated_assumed_bug]].
@ -128,16 +131,36 @@ whole cohort.
---
## OPEN THREAD 3 — Cert 0390 +7 (demand-side), no worksheet needed to diagnose
## THREAD 3 — Cert 0390 +7 — **CLOSED (S0380.210)**
**0390-2954-3640**: SAP +7 (calc 67 / lodged 60), PE 137 vs **165** (28/m²), CO2 12.3 vs
15. Large **360 m² age-F** detached. The boiler is **correctly** resolved (PCDB index
**9005** = "Firebird S", 86.4% winter — a real modern oil-boiler retrofit; not a bug).
The gap is a **demand-side under-count** (~28 PE/m² = thousands of kWh). Suspects:
cavity wall "as built, **partial** insulation (assumed)" routing; age-F roof "insulated
(assumed)"; floor (solid, no insulation) 81 W/K; ventilation/TB. Walk the demand
cascade (§2.4 helpers + the lodged register subsystem ratings) to localise. This is a
known long-standing gap (see the cert's `notes:` in `test_golden_fixtures.py`).
**0390-2954-3640** (detached, TFA 360, age F). The boiler was correctly resolved
(PCDB 9005 Firebird S, 86.4% winter); the gap was a single fabric mis-route. Walking
the §3 cascade localised it to the Main **cavity wall**: lodged `wall_construction=4`,
`wall_insulation_type=4` (as-built/assumed), description "Cavity wall, as built,
**partial insulation** (assumed)". The cascade routed it to the Table 6 **"Filled
cavity"** row (band F = 0.40) because `_described_as_insulated` matches the "partial
insulation" substring. Per **RdSAP 10 Table 6 (England)** an as-built partial-fill
cavity uses **"Cavity as built"** (band F = **1.0**), not filled — a genuine fill
lodges the distinct "Cavity wall, filled cavity" (`wall_insulation_type=2`). This
mirrors the worksheet-validated solid-brick rule from S0380.209 (cases 9/10).
Fix: new `_cavity_described_as_filled` predicate, used **only** in u_wall's cavity
filled-row branch, excludes "partial insulation" while keeping "insulated (assumed)"
→ filled. Wall HLC +53.6 W/K lifted all four metrics together: **SAP +7 → +0**,
PE 27.9745 → +0.5281, CO2 2.7134 → 0.1189. Bands I-M coincide († footnote) so
0535(M)/7536(L) are unaffected. Re-pinned in `test_golden_fixtures.py`.
**Diagnosis lesson / latent follow-up:** the fix collided with an existing test,
`test_cavity_as_built_insulated_assumed_uses_filled_cavity_row` (heat_transmission
tests). That test (from early "slice S-B25") asserts a cavity **"insulated (assumed)"**
→ filled row, citing only an *assumption* ("the assessor has determined the cavity is
filled"), **never worksheet-validated** — and it is the OPPOSITE conclusion from the
worksheet-backed solid-brick sibling. The narrow S0380.210 fix leaves it untouched
(no current cert exercises it at a band where as-built ≠ filled). **Open question for a
future worksheet:** does a cavity lodged "as built, insulated (assumed)" (type 4)
belong on the filled row (0.7 at E) or the as-built row (1.5 at E)? If a worksheet
says as-built, fold "insulated (assumed)" into the as-built routing too and retire
that test.
---
@ -145,7 +168,7 @@ known long-standing gap (see the cert's `notes:` in `test_golden_fixtures.py`).
| cert | SAP resid | diagnosis |
|---|---|---|
| 0390-2954-3640 | +7 | demand-side under-count (Thread 3); boiler eff correct |
| 0390-2954-3640 | ~~+7~~ **+0** | **CLOSED S0380.210** — cavity partial-insulation → as-built row |
| 9390-2722-3520 | +4 | community fuel-code collision → CO2 6× low (Thread 2) |
| 0240-0200-5706 | 1 | NOT a bug — unpreserved 2013+ pump; true SAP 72 |
| 2130-1033-4050 | +1 | minor fabric precision (multi-part solid-brick wall); low value |