Cohort residual slice 16a: 000480 detailed RR + exposed-floor lodgement

Updates 000480's build_epc to lodge the §3 worksheet inputs that the
prior Simplified Type 1 fallback was approximating:

- Detailed §3.10 RR (7 surfaces on Main): 1 flat ceiling 2.31 + 2
  stud walls 4.24 + 2 slopes 10.78 — all uninsulated (Table 17 row
  "none" → U=2.30); plus 2 gable walls 11.33 / 8.47 routed to party
  at U=0.25 (Table 4 "as common wall"). Per [[feedback-no-
  misleading-insulation-type]] uninsulated surfaces leave
  insulation_type unset.

- roof_insulation_thickness=300 on Ext1 (Main has no storey-below
  external roof — the RR floor 19.83 m² covers the entire Main
  footprint 15.28 m²). Back-solves from U=0.14 / Table 16 row 300mm.

- is_exposed_floor=True on Ext1 floor=0 — 000480 line 207 lodges
  "Exposed floor Ext1 17.01 × U=1.20" (28b), routing via Table 20
  rather than the BS EN ISO 13370 ground-contact cascade. The Ext1
  sits over an unheated space (passageway / over-garage), not soil.

Impact: SAP integer 65 → 67 mid-slice (the Simplified Type 1 fallback
was over-estimating the RR shell; detailed lodgement + exposed-floor
corrects toward worksheet). The remaining +6 overshoot is the LINE_31
gable_wall overcount bug — closed in slice 16b alongside the new e2e
test pin and 000477 door_count revision.

No tests pinned for 000480 yet — the new e2e test_elmhurst_000480_
end_to_end_sap_score_matches_pdf lands in 16b once the calculator
fix closes Δ=0. Existing 409 tests stay green at this commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-05-22 21:20:29 +00:00
parent a309b5fc90
commit 3aba735eee

View file

@ -24,6 +24,7 @@ from datatypes.epc.domain.epc_property_data import (
SapBuildingPart,
SapFloorDimension,
SapRoomInRoof,
SapRoomInRoofSurface,
SapVentilation,
SapWindow,
)
@ -66,6 +67,36 @@ def build_epc() -> EpcPropertyData:
],
sap_room_in_roof=SapRoomInRoof(
floor_area=19.83, construction_age_band="B",
# U985 §3 lines 198-202 + 211-212: 5 uninsulated surfaces
# (Table 17 row "none" → U=2.30) lodged on Main, plus 2
# gable walls routed to party at U=0.25 per Table 4. All
# RR surfaces sit on Main — the RR (19.83 m²) is larger
# than the Main storey footprint (15.28 m²) so Main has
# no External roof line (the entire Main roof is the RR).
detailed_surfaces=[
SapRoomInRoofSurface(
kind="flat_ceiling", area_m2=2.31,
insulation_thickness_mm=0,
),
SapRoomInRoofSurface(
kind="stud_wall", area_m2=4.24,
insulation_thickness_mm=0,
),
SapRoomInRoofSurface(
kind="stud_wall", area_m2=4.24,
insulation_thickness_mm=0,
),
SapRoomInRoofSurface(
kind="slope", area_m2=10.78,
insulation_thickness_mm=0,
),
SapRoomInRoofSurface(
kind="slope", area_m2=10.78,
insulation_thickness_mm=0,
),
SapRoomInRoofSurface(kind="gable_wall", area_m2=11.33),
SapRoomInRoofSurface(kind="gable_wall", area_m2=8.47),
],
),
wall_thickness_mm=380,
)
@ -82,6 +113,12 @@ def build_epc() -> EpcPropertyData:
total_floor_area_m2=17.01,
party_wall_length_m=7.84, heat_loss_perimeter_m=4.34,
floor=0,
# 000480 line 207: "Exposed floor Ext1 17.01 × U=1.20"
# — the Ext1 ground floor sits over an unheated space
# (passageway / over-garage), not soil. Routes via
# Table 20 (`u_exposed_floor`) to U=1.20 instead of
# the BS EN ISO 13370 ground-contact cascade.
is_exposed_floor=True,
),
SapFloorDimension(
room_height_m=3.09, # 2.84 internal + 0.25 floor structure
@ -92,6 +129,9 @@ def build_epc() -> EpcPropertyData:
],
# NB: no alternative wall on this cert (vs 000487 which had a
# 1.43 m² timber-frame alt wall on the extension).
# 000480 line 207: External roof Ext1 17.01 × U=0.14 → Table 16
# joist insulation 300 mm (or ≈ 270 mm row at 0.16). Pin 300 mm.
roof_insulation_thickness=300,
wall_thickness_mm=380,
)
return make_minimal_sap10_epc(