diff --git a/docs/baseline-downgrade-followups.md b/docs/baseline-downgrade-followups.md index 409db534..2157eb7f 100644 --- a/docs/baseline-downgrade-followups.md +++ b/docs/baseline-downgrade-followups.md @@ -3,16 +3,25 @@ Open items surfaced while fixing the full-SAP mapper / portfolio-796 downgrades. Each is **separate from** the full-SAP fix (`fix/baseline-downgrades`). -## 1. Older RdSAP mappers drop `mechanical_ventilation_kind` (calc-facing) +## 1. RdSAP ventilation mapping is inconsistent across schemas -**Severity: accuracy bug for MEV/MVHR dwellings.** +**Severity: accuracy bug for MEV/MVHR dwellings.** The mappers handle +`sap_ventilation` four different ways: -`mechanical_ventilation_kind` (the natural / MEV / MVHR ventilation **type**) is -mapped in **only `from_rdsap_schema_21_0_1`** ([mapper.py:2650], via -`_api_mechanical_ventilation_kind`). The other six API mappers — -`from_rdsap_schema_17_0/17_1/18_0/19_0/20_0_0/21_0_0` — build -`SapVentilation(sheltered_sides=…)` and **drop** the cert's `mechanical_ventilation` -field. (The full-SAP path maps it via `_sap_17_1_ventilation` — not affected.) +- `17_0` + full-SAP — build via `_sap_17_1_ventilation`, which **maps** + `mechanical_ventilation_kind`. ✅ +- `21_0_1` — rich inline `SapVentilation(...)` incl. the kind. ✅ +- **`17_1` / `18_0` / `20_0_0`** — built `SapVentilation(sheltered_sides=…)` and + **dropped** the kind. **Fixed in this PR** (mirror `_api_mechanical_ventilation_kind`). +- **`19_0` / `21_0_0`** — set **no `sap_ventilation` at all** → the dataclass + default empty object. They drop the **entire** ventilation block (sheltered + sides + kind + everything), not just the kind. **Still open** — a bigger, + separate consistency fix (give them a proper `sap_ventilation` construction, + mirroring 21.0.1), not a one-liner. + +Either way, an MEV/MVHR cert (`mechanical_ventilation ≠ 0`) is treated as +**natural** by the affected mappers — wrong §2 ventilation cascade (and heat +recovery). Natural certs (code `0`/`5` → `None`) are unaffected. - For **natural-ventilation** certs (`mechanical_ventilation = 0`, e.g. UPRN 100020603823 / property 726605) it's **benign** — unmapped → `None` defaults to @@ -25,11 +34,14 @@ The granular **counts** (fans/flues/vents) are *not* a bug: older RdSAP open-dat certs don't lodge them, and the calc correctly uses RdSAP Table-5 age defaults. `percent_draughtproofed` is mapped (top-level) and read by the calc. -**Fix:** mirror `mechanical_ventilation_kind=_api_mechanical_ventilation_kind(schema.mechanical_ventilation)` -into the six older RdSAP mappers. **Calc-facing → validate** with the RdSAP-21.0.1 -corpus (must hold 73.3% / MAE 0.774) plus an Elmhurst-anchored MEV/MVHR cert (the -corpus is natural-vent-dominated, so add a mechanical-vent `RealCertExpectation`). -Quantify blast radius: count older-RdSAP certs with `mechanical_ventilation ≠ 0`. +**Remaining fix (19.0 / 21.0.0):** give them a proper `sap_ventilation` +construction mirroring 21.0.1. **Calc-facing → validate** with the RdSAP-21.0.1 +corpus (must hold 73.3% / MAE 0.774) plus an **Elmhurst-anchored MEV/MVHR +`RealCertExpectation`** (the corpus is natural-vent-dominated, so the kind change +isn't exercised by it). Quantify blast radius: count older-RdSAP certs with +`mechanical_ventilation ≠ 0`. The 17.1/18.0/20.0.0 fix in this PR is guarded by a +mapper-level MVHR test + the corpus/mapper-corpus staying green, with the Elmhurst +MEV/MVHR anchor as the SAP-accuracy fast-follow. ## 2. FE "Main Fuel: Unknown" is FE-side, not a Model mapper gap