An unlodged roof type with ND thickness gets no roof recommendation 🟩

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-02 11:20:55 +00:00
parent 0efae77fd2
commit 6d812d99c5
2 changed files with 24 additions and 3 deletions

View file

@ -46,6 +46,16 @@ extends the codebase's existing precedent (`_PRE_1950_AGE_CODES = {A,B,C,D}`
in the mapper's code-8 rule; pinned by cert 001479 Ext2 at U=2.30) from the
scoring path to eligibility.
**Sentinel resolution requires a KNOWN pitched/thatched roof type.** An
unlodged `roof_construction_type` reaching the loft fallback can be a **party
ceiling** — gov-API codes 6/7 ("(another dwelling above)" / thatch with
additional insulation) map the type to `None`, and real code-7 certs lodge
`"ND"` — with zero roof heat loss (RdSAP 10 Table 18), so insulating it
contradicts the dwelling. An unlodged type therefore keeps the explicit-0-only
trigger (the pre-ADR behaviour for that shape); only a type containing
`pitched`/`thatch` (or the sloping/vaulted branch, known by construction)
resolves sentinels by age band.
**Coherence rule (load-bearing):** sentinel resolution must never make an
undefined cert *more* eligible than an explicitly-lodged one. An explicit
50 mm lodgement is not eligible today, so `"ND"` on a band-E/F ("limited

View file

@ -129,9 +129,20 @@ def recommend_roof_insulation(
if "no access" in roof_type:
return None # the roof void can't be reached to insulate it
if not _pitched_roof_is_uninsulated(
main.roof_insulation_thickness, main.construction_age_band
):
# Sentinel resolution needs a KNOWN pitched/thatched roof (ADR-0047). An
# unlodged type reaching this fallback can be a party ceiling — gov-API
# codes 6/7 ("(another dwelling above)" / insulated thatch) map the type
# to None and real code-7 certs lodge "ND" — with zero roof heat loss
# (RdSAP 10 Table 18), so only an explicit 0 may trigger it.
known_pitched: bool = "pitched" in roof_type or "thatch" in roof_type
uninsulated: bool = (
_pitched_roof_is_uninsulated(
main.roof_insulation_thickness, main.construction_age_band
)
if known_pitched
else main.roof_insulation_thickness == 0
)
if not uninsulated:
return None
return _roof_recommendation(
epc,