From 3d315a0d9033c66bcb1157af2cacdb9449629876 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Mon, 25 May 2026 18:09:45 +0000 Subject: [PATCH] Slice 82: bulk-update cohort 000490 hand-built for Cat A diff parity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes 31 of 32 mapper-vs-hand-built load-bearing divergences by populating fields the Elmhurst mapper extracts from Summary_000490. pdf but the original hand-built left at their `make_minimal_sap10_ epc` / dataclass-default values. Every change is cascade-equivalent — all 11 `_FIXTURE_PINS["000490"]` SapResult pins remain GREEN against worksheet `SAP value 57.3979`. 000490-specific deltas vs prior cohort certs: - `dwelling_type="End-Terrace house"`, `built_form="End-Terrace"` — first end-terrace fixture (vs Mid-Terrace / Enclosed Mid-Terrace on the other 4 cohort certs); sheltered_sides=1 is already set on the existing SapVentilation block. - `number_of_storeys=2` — 000490 has no room-in-roof (2-storey main + 2-storey extension), so dwelling height is 2 (vs 3 for the RR cohort certs). - `number_baths=1` on sap_heating — mapper extracts 1 from Summary §16; cascade-equivalent (Appendix J §1a defaults to 1 if absent). - `wall_thickness_measured=True` on **both** bps (Summary §7 lodges measured Wall Thickness 400 mm). Standard Cat A additions (per Slice 72/75/78 pattern): floor descriptive fields per bp, roof_insulation_location, 6 ventilation zero counts, draught_lobby=True, pressure_test="Not available", top-level descriptive strings + booleans + extensions_count=1, blocked_chimneys_count=0, shower_outlets=Non-electric shower, central_heating_pump_age_str="Unknown". Diff count: 32 → **1**. Remaining diff is `sap_windows: LEN 6 vs 3` — closes via Slice 83. Pyright net-zero on the touched fixture. Co-Authored-By: Claude Opus 4.7 --- .../tests/_elmhurst_worksheet_000490.py | 58 +++++++++++++++++-- 1 file changed, 54 insertions(+), 4 deletions(-) diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py index 05313170..98b86231 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py +++ b/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py @@ -30,6 +30,8 @@ from datatypes.epc.domain.epc_property_data import ( SapFloorDimension, SapVentilation, SapWindow, + ShowerOutlet, + ShowerOutlets, ) from domain.ml.tests._fixtures import ( make_main_heating_detail, @@ -51,13 +53,23 @@ _WC_CAVITY = 4 def build_epc() -> EpcPropertyData: - """EpcPropertyData mirroring the Elmhurst 000490 inputs.""" + """EpcPropertyData mirroring the Elmhurst 000490 inputs. + + Field-level parity with `from_elmhurst_site_notes(Summary_000490. + pdf)` for the load-bearing field allow-list — cascade-equivalent + encoding-only fields (descriptive floor/roof strings, ventilation + zero counts) are populated explicitly to eliminate noise without + altering the SAP cascade output (the 11 1e-4 pins in + `test_e2e_elmhurst_sap_score.py` remain GREEN against the worksheet + PDF's `SAP value 57.3979`). + """ main = SapBuildingPart( identifier=BuildingPartIdentifier.MAIN, construction_age_band="B", wall_construction=_WC_CAVITY, wall_insulation_type=4, - wall_thickness_measured=False, + # Summary §7 lodges Wall Thickness 400 mm explicitly; matches mapper. + wall_thickness_measured=True, party_wall_construction=0, # "U Unable to determine" → U=0.25 roof_insulation_thickness=300, # Table 16 "300 mm joists" → U=0.14 sap_floor_dimensions=[ @@ -75,13 +87,20 @@ def build_epc() -> EpcPropertyData: ), ], wall_thickness_mm=400, + # Mapper-extracted descriptive fields (cascade reads int codes + # on SapFloorDimension; these carry the lodged Summary text). + floor_type="Ground floor", + floor_construction_type="Suspended timber", + floor_insulation_type_str="As built", + floor_u_value_known=False, + roof_insulation_location="Joists", ) extension = SapBuildingPart( identifier=BuildingPartIdentifier.EXTENSION_1, construction_age_band="B", wall_construction=_WC_CAVITY, wall_insulation_type=4, - wall_thickness_measured=False, + wall_thickness_measured=True, party_wall_construction=0, roof_insulation_thickness=300, sap_floor_dimensions=[ @@ -104,6 +123,11 @@ def build_epc() -> EpcPropertyData: ), ], wall_thickness_mm=400, + floor_type="Above unheated space", + floor_construction_type="Suspended timber", + floor_insulation_type_str="As built", + floor_u_value_known=False, + roof_insulation_location="Joists", ) # door_count=2 matches the worksheet's 3.70 m² of total door area: # Elmhurst lodges 1 oversized 3.7 m × 1.0 m door, our cascade uses the @@ -113,7 +137,7 @@ def build_epc() -> EpcPropertyData: # 28kW, 2004-2012, winter eff 88.2%, summer eff 79.6%). Lodging it on the # MainHeatingDetail routes `cert_to_inputs` into the PCDB precedence # cascade rather than the Table 4a category-2 default (80%). - return make_minimal_sap10_epc( + epc = make_minimal_sap10_epc( total_floor_area_m2=66.06, country_code="ENG", postcode="bd19 3TF", @@ -124,6 +148,11 @@ def build_epc() -> EpcPropertyData: low_energy_fixed_lighting_bulbs_count=8, sap_windows=list(SECTION_6_VERTICAL_WINDOWS), percent_draughtproofed=100, + extensions_count=1, + blocked_chimneys_count=0, + dwelling_type="End-Terrace house", + built_form="End-Terrace", + property_type="House", sap_ventilation=SapVentilation( extract_fans_count=2, sheltered_sides=1, @@ -131,6 +160,14 @@ def build_epc() -> EpcPropertyData: # the worksheet, same pattern as 000480. has_suspended_timber_floor=False, has_draught_lobby=False, + open_flues_count=0, + closed_flues_count=0, + boiler_flues_count=0, + other_flues_count=0, + passive_vents_count=0, + flueless_gas_fires_count=0, + draught_lobby=True, + pressure_test="Not available", ), sap_heating=make_sap_heating( main_heating_details=[ @@ -140,8 +177,21 @@ def build_epc() -> EpcPropertyData: ), ], secondary_heating_type=691, + # 000490 cert: number_baths=1 (mapper extracts this). Cascade- + # equivalent to leaving None — Appendix J §1a defaults to 1 + # when nothing is lodged. + number_baths=1, ), ) + # Top-level cert-lodgement booleans the mapper surfaces. + epc.has_conservatory = False + epc.any_unheated_rooms = False + epc.number_of_storeys = 2 + epc.sap_heating.shower_outlets = ShowerOutlets( + shower_outlet=ShowerOutlet(shower_outlet_type="Non-electric shower"), + ) + epc.sap_heating.main_heating_details[0].central_heating_pump_age_str = "Unknown" + return epc # ============================================================================