diff --git a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py index 94a3b927..c3a1f4df 100644 --- a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py +++ b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py @@ -4330,3 +4330,32 @@ def test_from_elmhurst_site_notes_matches_hand_built_000516() -> None: f"hand-built EpcPropertyData for cohort cert 000516:\n " + "\n ".join(diffs) ) + + +def test_elmhurst_jacket_cylinder_insulation_maps_to_loose_jacket_code_2() -> None: + # Arrange — an Elmhurst §15.1 "Cylinder Insulation Type: Jacket" + # lodging is a loose jacket, which SAP 10.2 Table 2 Note 1 gives a + # separate (higher) storage-loss factor than factory foam. The SAP10 + # `cylinder_insulation_type` enum uses 2 for loose jacket (1 = factory + # foam), matching the GOV.UK API path — so the Summary "Jacket" label + # must resolve to 2 for cross-mapper parity, and so the + # loose-jacket storage-loss branch (S0380.224) fires. Observed on the + # simulated-case-19 worksheet (210 L jacket cylinder + storage heaters). + from datatypes.epc.domain.mapper import _elmhurst_cylinder_insulation_code # pyright: ignore[reportPrivateUsage] + + # Act + code = _elmhurst_cylinder_insulation_code("Jacket", cylinder_present=True) + + # Assert + assert code == 2 + + +def test_elmhurst_foam_cylinder_insulation_still_maps_to_factory_code_1() -> None: + # Arrange — regression guard: the factory-foam label is unchanged. + from datatypes.epc.domain.mapper import _elmhurst_cylinder_insulation_code # pyright: ignore[reportPrivateUsage] + + # Act + code = _elmhurst_cylinder_insulation_code("Foam", cylinder_present=True) + + # Assert + assert code == 1 diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index caf09b6f..98a341b9 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -4710,8 +4710,14 @@ _ELMHURST_CYLINDER_SIZE_LABEL_TO_SAP10: Dict[str, int] = { # which SAP 10.2 Table 2 Note 2 treats as factory-applied PU foam). # Other labels (Loose Jacket, None) raise `UnmappedElmhurstLabel` # until a fixture exercises them. +# SAP10 cylinder_insulation_type enum: 1 = factory-applied foam, +# 2 = loose jacket (matching the GOV.UK API codes). SAP 10.2 Table 2 +# Note 1 gives loose jacket a separate, ~2× higher storage-loss factor; +# the cascade's loose-jacket branch is wired (S0380.224), so "Jacket" +# resolves to 2 for cross-mapper parity with the API path. _ELMHURST_CYLINDER_INSULATION_LABEL_TO_SAP10: Dict[str, int] = { "Foam": 1, + "Jacket": 2, }