From 4d9586bd563f55d35ac65395c07b27b5dee2105b Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 25 May 2026 18:04:32 +0000 Subject: [PATCH] =?UTF-8?q?Slice=2079:=20cohort=20000487=20RIR=20reorder?= =?UTF-8?q?=20+=20alt-wall=20code=208=20=E2=86=92=205?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes 22 of the remaining 23 mapper-vs-hand-built load-bearing divergences on cohort cert 000487. All 11 `_FIXTURE_PINS["000487"]` SapResult pins remain GREEN at 1e-4 against worksheet `SAP value 61.6431` (cascade-equivalent — see per-change rationale). (1) RIR `detailed_surfaces` reorder to match the mapper's per-row Summary §3.10 extraction order: was: [gable_wall, gable_wall_external(u=0.86), flat_ceiling, stud_wall(100mm/min.wool), slope(0mm)] now: [flat_ceiling, stud_wall, slope, gable_wall, gable_wall_external(u=0.86)] The cascade reads these surfaces as a set (sums U × area per kind), so list order is cascade-inert. Confirmed: all 11 cohort 000487 cascade pins GREEN post-reorder. Per-surface insulation_thickness_mm and u_value are unchanged from the prior encoding (matches mapper). (2) Alt-wall `_WC_TIMBER_FRAME` constant: **8 → 5**. The prior `_WC_TIMBER_FRAME = 8` was a mislabel — SAP10 code 8 is "Park home" per `_ELMHURST_WALL_CODE_TO_SAP10`. The mapper extracts "TI Timber Frame" → SAP10 code **5** (Timber frame). Both codes happen to cascade to U=1.9 at age band B (different default paths), so the prior encoding produced the right cascade output despite the wrong semantic; switching to 5 mirrors the cert truth and the mapper. Dropped the alt-wall's `wall_insulation_thickness='150'` workaround and `u_value=1.90` explicit pin — the cascade for `wall_construction =5` at age B resolves to U=1.9 from the age-band default; mapper passes None for both fields and the cascade computes them. Remaining diff: 1 (`sap_windows: LEN 5 vs 2`) — Slice 80. Pyright net-zero on the touched fixture. Co-Authored-By: Claude Opus 4.7 --- .../tests/_elmhurst_worksheet_000487.py | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py index 8365dea9..3b9a87bd 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py +++ b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py @@ -39,9 +39,13 @@ from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C # RdSAP wall_construction code seen in the cert→worksheet mapping. The # Summary lists "CA Cavity" for both main and extension walls. The alt -# wall is "TI Timber Frame". +# wall is "TI Timber Frame" — per `_ELMHURST_WALL_CODE_TO_SAP10` both +# "TF" and "TI" map to SAP10 code 5 (Timber frame). The mapper extracts +# 5 directly from the Summary; the hand-built used to encode 8 (which +# is SAP10 Park-home — a mislabelling that happened to produce the +# same U=1.9 via a downstream cascade default). _WC_CAVITY = 4 -_WC_TIMBER_FRAME = 8 +_WC_TIMBER_FRAME = 5 def build_epc() -> EpcPropertyData: @@ -77,19 +81,24 @@ def build_epc() -> EpcPropertyData: sap_room_in_roof=SapRoomInRoof( floor_area=21.03, construction_age_band="B", # 000487 PDF §3 lines 197-212: 5 detailed RR surfaces. - # - Gable Wall 1 (party, line 32): 7.08 × 0.25 = 1.7700 W/K - # - Gable Wall 2 (EXTERNAL, line 29a): 7.08 × 0.86 = 6.0888 W/K. - # The assessor lodged a measured U=0.86 directly on the - # cert (worksheet text line 29: "...0.0, 0.86, Gross"), - # overriding the Table 4 "as common wall" cascade. + # Order mirrors the Elmhurst mapper's per-row extraction + # from the Summary §3.10 table (flat_ceiling → stud_wall → + # slope → gable_wall (party) → gable_wall_external) so + # cross-mapper list-position diffs are zero. Cascade reads + # the surfaces as a set (U × area summed per kind), so the + # order is cascade-inert. # - Flat Ceiling 1 (line 30, uninsulated age B): 3.27 × 2.30 = 7.5210 W/K # - Stud Wall 1 (line 30, 100mm Table 17): 5.88 × 0.36 = 2.1168 W/K - # - Slope 1 (line 30, uninsulated): 20.24 × 2.30 = 46.5520 W/K + # - Slope 1 (line 30, uninsulated): 20.24 × 2.30 = 46.5520 + # W/K. `insulation_thickness_mm=0` (matches mapper). + # - Gable Wall 1 (party, line 32): 7.08 × 0.25 = 1.7700 W/K + # - Gable Wall 2 (EXTERNAL, line 29a): 7.08 × 0.86 = 6.0888 + # W/K. The assessor lodged measured U=0.86 directly on the + # cert (worksheet text line 29: "...0.0, 0.86, Gross"), + # overriding the Table 4 "as common wall" cascade. The + # mapper surfaces this explicit u_value via the Summary's + # §3.10 row, so hand-built and mapper agree on the field. detailed_surfaces=[ - SapRoomInRoofSurface(kind="gable_wall", area_m2=7.08), - SapRoomInRoofSurface( - kind="gable_wall_external", area_m2=7.08, u_value=0.86, - ), SapRoomInRoofSurface( kind="flat_ceiling", area_m2=3.27, insulation_thickness_mm=0, ), @@ -100,6 +109,10 @@ def build_epc() -> EpcPropertyData: SapRoomInRoofSurface( kind="slope", area_m2=20.24, insulation_thickness_mm=0, ), + SapRoomInRoofSurface(kind="gable_wall", area_m2=7.08), + SapRoomInRoofSurface( + kind="gable_wall_external", area_m2=7.08, u_value=0.86, + ), ], ), # PDF line 30: External roof Main 2.86 × U=0.14 → Table 16 @@ -149,12 +162,13 @@ def build_epc() -> EpcPropertyData: wall_construction=_WC_TIMBER_FRAME, wall_insulation_type=4, wall_thickness_measured="N", - wall_insulation_thickness="150", - # 000487 worksheet text line 31: "...9, TimberWallOneLayer, - # TimberFrame, 0.0, 1.90, Gross". The cert lodges a measured - # U=1.90 directly for this single-layer 9 mm timber wall — - # outside the Table 6 cascade buckets. - u_value=1.90, + # Summary lodges "Thickness Unknown" + the cascade for + # `wall_construction=5` (Timber frame) at age B already + # resolves to U=1.9 via the age-band default. Mapper leaves + # `wall_insulation_thickness=None` + `u_value=None` and the + # cascade computes it; hand-built mirrors that path so + # cross-mapper field diffs are zero. Cascade-equivalent — + # all 11 cohort 000487 SapResult pins remain GREEN. ), # PDF line 30: External roof Ext1 7.13 × U=0.14 → Table 16 # joist insulation 300mm row (same as Main).