mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 72: bulk-update cohort 000477 hand-built for Cat A diff parity
Closes 23 of 24 mapper-vs-hand-built load-bearing divergences by
populating fields the Elmhurst mapper extracts from Summary_000477.
pdf but the original cohort hand-built left at their `make_minimal_
sap10_epc` / dataclass-default values. Every change is cascade-
equivalent — none alter `_FIXTURE_PINS["000477"]` SapResult fields
(all 11 1e-4 pins remain GREEN against worksheet `SAP value 65.0057`).
Mirrors the Slice 64 pattern on the cohort 000474 hand-built:
SapBuildingPart additions (Main only — 000477 is a single-bp mid-
terrace, no extension):
- `wall_thickness_measured`: False → True. Summary §7 lodges Wall
Thickness 380 mm explicitly; the cascade doesn't consume this flag.
- `floor_type`, `floor_construction_type`, `floor_insulation_type_
str`, `floor_u_value_known`: surfaced from Summary §9 ("G Ground
floor" / "T Suspended timber" / "A As built" / U-value Known = No).
Cascade reads the int codes on SapFloorDimension, not these strings.
- `roof_insulation_location="Joists"`: surfaced from Summary §8.
SapVentilation additions (all cascade-equivalent — `None` defaults to
0 throughout the §2 cascade chain):
- 6 explicit zero counts (`open_flues`, `closed_flues`, `boiler_
flues`, `other_flues`, `passive_vents`, `flueless_gas_fires`)
- `pressure_test="Not available"` (descriptive — cert lodges no test)
- `draught_lobby=True` (legacy field; cascade reads `has_draught_
lobby=False` which stays as set)
Top-level additions via `make_minimal_sap10_epc`:
- `blocked_chimneys_count=0`, `dwelling_type="Mid-Terrace house"`,
`built_form="Mid-Terrace"`, `property_type="House"`
Post-construction mutations (helper doesn't expose these as kwargs):
- `has_conservatory=False`, `any_unheated_rooms=False`,
`number_of_storeys=3` (cohort 000477 has ground + first + RIR)
- `sap_heating.shower_outlets=ShowerOutlets(Non-electric shower)`
- `sap_heating.main_heating_details[0].central_heating_pump_age_str=
"Unknown"`
Diff count: 24 → **1**. The remaining diff is structural:
- `sap_windows: LEN 7 vs 3` — mapper extracts 1:1 from §11 table;
the hand-built collapses by glazing-type group, preserving total
area. Cascade-equivalent but not field-equal. Closes via the same
1:1 expansion that Slice 69 applied to cohort 000474 (5 → 7).
11 cohort 000477 cascade pins still GREEN; pyright net-zero on the
touched fixture file.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
69bfac2204
commit
6d9cf47344
1 changed files with 63 additions and 3 deletions
|
|
@ -26,6 +26,8 @@ from datatypes.epc.domain.epc_property_data import (
|
|||
SapRoomInRoofSurface,
|
||||
SapVentilation,
|
||||
SapWindow,
|
||||
ShowerOutlet,
|
||||
ShowerOutlets,
|
||||
)
|
||||
from domain.ml.tests._fixtures import (
|
||||
make_main_heating_detail,
|
||||
|
|
@ -47,13 +49,25 @@ _WC_CAVITY = 4
|
|||
|
||||
|
||||
def build_epc() -> EpcPropertyData:
|
||||
"""EpcPropertyData mirroring the Elmhurst 000477 inputs."""
|
||||
"""EpcPropertyData mirroring the Elmhurst 000477 inputs.
|
||||
|
||||
Field-level parity with `from_elmhurst_site_notes(Summary_000477.
|
||||
pdf)` for the load-bearing field allow-list — every cohort hand-
|
||||
built doubles as the ground-truth diff target for the Elmhurst
|
||||
mapper. Cascade-equivalent encoding-only fields (descriptive floor/
|
||||
roof strings, ventilation zero counts) are populated explicitly to
|
||||
eliminate noise from `test_from_elmhurst_site_notes_matches_hand_
|
||||
built_000477` diffs without altering the SAP cascade output (the
|
||||
Section-10a 1e-4 pins in `test_e2e_elmhurst_sap_score.py` remain
|
||||
GREEN against the worksheet PDF).
|
||||
"""
|
||||
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 380 mm explicitly; matches mapper.
|
||||
wall_thickness_measured=True,
|
||||
party_wall_construction=0, # "Unable to determine" → u_party_wall = 0.25
|
||||
sap_floor_dimensions=[
|
||||
SapFloorDimension(
|
||||
|
|
@ -99,8 +113,16 @@ def build_epc() -> EpcPropertyData:
|
|||
# joist insulation 300mm (or ≈ 270mm row at 0.16). Pin 300mm.
|
||||
roof_insulation_thickness=300,
|
||||
wall_thickness_mm=380,
|
||||
# Mapper-extracted descriptive fields (cascade reads the int
|
||||
# codes on SapFloorDimension; these strings carry the lodged
|
||||
# Summary text for cross-mapper field parity).
|
||||
floor_type="Ground floor",
|
||||
floor_construction_type="Suspended timber",
|
||||
floor_insulation_type_str="As built",
|
||||
floor_u_value_known=False,
|
||||
roof_insulation_location="Joists",
|
||||
)
|
||||
return make_minimal_sap10_epc(
|
||||
epc = make_minimal_sap10_epc(
|
||||
total_floor_area_m2=77.58,
|
||||
country_code="ENG",
|
||||
postcode="bd3 9DR",
|
||||
|
|
@ -116,12 +138,29 @@ def build_epc() -> EpcPropertyData:
|
|||
percent_draughtproofed=100,
|
||||
low_energy_fixed_lighting_bulbs_count=SECTION_5_BULB_COUNT_LEL,
|
||||
sap_windows=list(SECTION_6_VERTICAL_WINDOWS),
|
||||
blocked_chimneys_count=0,
|
||||
dwelling_type="Mid-Terrace house",
|
||||
built_form="Mid-Terrace",
|
||||
property_type="House",
|
||||
sap_ventilation=SapVentilation(
|
||||
extract_fans_count=2,
|
||||
sheltered_sides=2,
|
||||
has_suspended_timber_floor=True,
|
||||
suspended_timber_floor_sealed=False,
|
||||
has_draught_lobby=False,
|
||||
# SAP10.2 §2 — explicit zero counts match the mapper, which
|
||||
# parses the Summary's "No. of <flue>" rows. None / 0 are
|
||||
# cascade-equivalent (the (11)+(13a)+(13b) chain treats
|
||||
# absent counts as zero), but setting 0 explicitly closes
|
||||
# the cross-mapper field diff for free.
|
||||
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=[
|
||||
|
|
@ -134,6 +173,27 @@ def build_epc() -> EpcPropertyData:
|
|||
number_baths=0, # PDF: Total number of baths in property = 0
|
||||
),
|
||||
)
|
||||
# Top-level cert-lodgement booleans / counts the Elmhurst mapper
|
||||
# surfaces from the Summary PDF but `make_minimal_sap10_epc` doesn't
|
||||
# expose as kwargs. Set post-construction (dataclass is non-frozen).
|
||||
epc.has_conservatory = False
|
||||
epc.any_unheated_rooms = False
|
||||
epc.number_of_storeys = 3
|
||||
# `make_sap_heating` doesn't expose `shower_outlets` as a kwarg; the
|
||||
# Elmhurst mapper surfaces it from Summary §16. Setting here for
|
||||
# cross-mapper field parity. Cascade-equivalent: a non-electric
|
||||
# mixer outlet with no WWHRS is what Appendix J's flow-rate back-
|
||||
# solve already assumes for this fixture (see fixture's
|
||||
# MIXER_SHOWER_FLOW_RATES_L_PER_MIN = (7.0,) for 1 mixer outlet).
|
||||
epc.sap_heating.shower_outlets = ShowerOutlets(
|
||||
shower_outlet=ShowerOutlet(shower_outlet_type="Non-electric shower"),
|
||||
)
|
||||
# Summary §14 "Heat pump age: Unknown" — surfaced by the Elmhurst
|
||||
# mapper as the str dual-encoding that internal_gains.py reads.
|
||||
# `make_main_heating_detail` doesn't expose the str kwarg, so set
|
||||
# here post-construction for cross-mapper field parity.
|
||||
epc.sap_heating.main_heating_details[0].central_heating_pump_age_str = "Unknown"
|
||||
return epc
|
||||
|
||||
|
||||
# ============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue