mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
fix(mapper): floor_heat_loss code 8 → no floor heat loss (extension over heated space)
API floor_heat_loss=8 is observed on EXTENSION building parts whose floor sits over a heated space within the SAME dwelling (an upper-storey extension over a heated room). RdSAP 10 §3 gives an internal floor between heated storeys no floor heat loss — mechanically identical to a code-6 party floor. `_api_floor_type_str` had no entry for 8, raising UnmappedApiCode and blocking certs 0370-2254-6520-2426-5971 and 0997-1206-9806-0715-2904. Map code 8 to the code-6 no-heat-loss string "(another dwelling below)" (consumed by heat_transmission's party-floor suppression; != "Ground floor" so the §5 (12) suspended-timber rule stays inert). Empirically confirmed against both certs: the no-heat-loss treatment lands them within 0.5 of lodged (0370-2254 68.92 vs 69; 0997-1206 40.68 vs 41), whereas Ground-floor / unheated / external mappings miss 0997 by ~4 SAP. Eval computed 906→908. Regression green (only the pre-existing test_total_floor_area fails); pyright net-zero (38=38). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f40485887d
commit
1c5675a063
2 changed files with 37 additions and 3 deletions
|
|
@ -2647,16 +2647,32 @@ def _api_floor_construction_str(value: Optional[int]) -> Optional[str]:
|
|||
# the §5 (12) suspended-timber rule stays
|
||||
# inert (short-circuits exactly as None did).
|
||||
# 7 = "Ground floor" — typical ground-floor heat loss
|
||||
# 8 = "(another dwelling below)" — observed on EXTENSION building parts
|
||||
# whose floor sits over a heated space
|
||||
# within the SAME dwelling (an upper-storey
|
||||
# extension over a heated room). RdSAP 10 §3
|
||||
# gives an internal floor between heated
|
||||
# storeys no floor heat loss — mechanically
|
||||
# identical to a code-6 party floor, so it
|
||||
# reuses that suppression string (consumed
|
||||
# by heat_transmission's party-floor
|
||||
# override; != "Ground floor" so §5 (12)
|
||||
# stays inert). Empirically confirmed: both
|
||||
# code-8 certs land within 0.5 of lodged
|
||||
# (0370-2254 68.9 vs 69; 0997-1206 40.7 vs
|
||||
# 41), while Ground-floor / unheated /
|
||||
# external mappings miss 0997 by ~4 SAP.
|
||||
#
|
||||
# Codes 4/5/8+ are not yet observed in any fixture; the strict-raise
|
||||
# path catches them at the extraction boundary so the next cert forces
|
||||
# an explicit mapping decision.
|
||||
# Codes 4/5 are not yet observed in any fixture; the strict-raise path
|
||||
# catches them at the extraction boundary so the next cert forces an
|
||||
# explicit mapping decision.
|
||||
_API_FLOOR_HEAT_LOSS_TO_FLOOR_TYPE: Dict[int, Optional[str]] = {
|
||||
1: "To external air",
|
||||
2: "To unheated space",
|
||||
3: "To unheated space",
|
||||
6: "(another dwelling below)",
|
||||
7: "Ground floor",
|
||||
8: "(another dwelling below)",
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -914,6 +914,24 @@ class TestApiFloorTypeCode:
|
|||
# Act / Assert
|
||||
assert _api_floor_type_str(7) == "Ground floor"
|
||||
|
||||
def test_code_8_maps_to_no_floor_heat_loss(self) -> None:
|
||||
# Arrange — code 8 is observed on EXTENSION building parts whose
|
||||
# floor sits over a heated space within the same dwelling (an
|
||||
# upper-storey extension over a heated room). RdSAP 10 §3 treats an
|
||||
# internal floor between heated storeys as no floor heat loss —
|
||||
# mechanically identical to a code-6 party floor. Empirically
|
||||
# confirmed: routing code 8 to the no-heat-loss treatment lands
|
||||
# both code-8 certs within 0.5 of lodged (0370-2254 68.9 vs 69;
|
||||
# 0997-1206 40.7 vs 41), whereas Ground-floor / unheated / external
|
||||
# mappings miss 0997 by ~4 SAP. Reuses code 6's suppression string
|
||||
# (consumed by heat_transmission's party-floor override); it is
|
||||
# != "Ground floor", so the §5 (12) suspended-timber rule stays
|
||||
# inert. Pre-this, code 8 raised UnmappedApiCode, blocking the cert.
|
||||
from datatypes.epc.domain.mapper import _api_floor_type_str # pyright: ignore[reportPrivateUsage]
|
||||
|
||||
# Act / Assert — no-heat-loss signal (not None, not "Ground floor").
|
||||
assert _api_floor_type_str(8) == "(another dwelling below)"
|
||||
|
||||
|
||||
class TestApiFloorConstructionCode:
|
||||
"""`_api_floor_construction_str` maps the GOV.UK API integer
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue