Model/docs/baseline-downgrade-followups.md
Khalim Conn-Kowlessar b2c74dbf5b docs: ventilation mapping inconsistency — 17.1/18.0/20.0.0 fixed, 19.0/21.0.0 open
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:46:01 +00:00

68 lines
3.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Follow-ups from the full-SAP baseline-downgrade work (ADR-0037)
Open items surfaced while fixing the full-SAP mapper / portfolio-796 downgrades.
Each is **separate from** the full-SAP fix (`fix/baseline-downgrades`).
## 1. RdSAP ventilation mapping is inconsistent across schemas
**Severity: accuracy bug for MEV/MVHR dwellings.** The mappers handle
`sap_ventilation` four different ways:
- `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
natural in the §2 cascade.
- For **MEV/MVHR** certs (`mechanical_ventilation ≠ 0`) the calculator treats the
dwelling as **naturally ventilated**, getting the SAP §2 ventilation cascade
(and any heat recovery) wrong → mis-scored SAP.
The granular **counts** (fans/flues/vents) are *not* a bug: older RdSAP open-data
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.
**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
`main_fuel_type` (the gov fuel **code**) **is** populated Model-side — UPRN
10093412452 (709791) → `1`, UPRN 100020603823 (726605) → `26` — and is persisted
(`epc_main_heating_detail.main_fuel_type`). So the panel's "Main Fuel: Unknown"
is the **front-end** either not mapping the code → fuel name or reading a field we
don't populate. Needs an FE-repo (Drizzle/Next) check, not a Model change.
## 3. Survivor clusters from the post-fix population sweep
`scripts/hyde/case_a_population_sweep.py`: the representative sample rebaselined
cleanly (0 survivors), but the worst-old-drop sample held **28 survivors**
(lodged A/B → new C/D, 1525 SAP) in tight UPRN clusters (new-build blocks),
spanning multiple schemas (16.0/16.1/17.1/18.0.0) and heating types. No single
mapper-gap signature → likely genuine SAP-2012→10.2 drops for very-high-lodged
new-builds, but **triage one in Elmhurst** to confirm genuine vs a residual calc
issue before trusting the cohort.
## 4. Predicted-property display path (e.g. property 721167)
721167 has **no lodged EPC** (predicted). Its Heating-Control / Main-Fuel /
Ventilation Unknowns come from the prediction + landlord-override **overlay** not
populating the display fields — a separate path from the lodged-cert mappers.