diff --git a/tests/repositories/epc/test_epc_round_trip.py b/tests/repositories/epc/test_epc_round_trip.py index 5def5e7e8..d18a2bc0d 100644 --- a/tests/repositories/epc/test_epc_round_trip.py +++ b/tests/repositories/epc/test_epc_round_trip.py @@ -240,3 +240,45 @@ def test_building_part_wall_insulation_thickness_preserves_int( value = reloaded.sap_building_parts[0].wall_insulation_thickness assert value == 100 assert isinstance(value, int) + + +def test_rafter_insulation_thickness_round_trips(db_engine: Engine) -> None: + # RdSAP 10 §5.11.2 — a roof insulated AT RAFTERS lodges its insulation + # thickness in `rafter_insulation_thickness`, NOT `roof_insulation_thickness` + # (which stays null for rafter roofs, since rafters aren't loft joists). + # `heat_transmission.py:922` prefers it when `roof_insulation_location == 1` + # so the MEASURED Table 16 column (2) row applies. It had no DB column, so it + # was silently dropped on save and every at-rafters roof fell back to the + # Table 18 column (2) unknown-thickness default (persist != score). + # + # Real impact: property 749719 lodges "250mm" -> Table 16 col (2) U 0.23. + # Dropped, the roof bills at U 2.30 — a 10x error worth -9.8 SAP (lodged 73, + # calculated 63.2) that moved the dwelling a whole band, C -> D. + # + # Note this is an RdSAP INPUT (an insulation thickness feeding the standard + # cascade), not a lodged U-value. The sibling `wall/roof/floor_u_value` and + # `wall_is_basement` fields are full-SAP artefacts and are deliberately NOT + # persisted — see the `_UNPERSISTED_ALLOWLIST` note in + # test_epc_persistence_field_coverage.py. + from dataclasses import replace + + # Arrange — a green fixture carrying a measured at-rafters thickness. + original = _load_epc("RdSAP-Schema-21.0.1") + assert original.sap_building_parts, "fixture must have a building part" + bp0 = replace( + original.sap_building_parts[0], + rafter_insulation_thickness="250mm", + ) + original = replace( + original, sap_building_parts=[bp0, *original.sap_building_parts[1:]] + ) + + # Act + with Session(db_engine) as session: + epc_property_id = EpcPostgresRepository(session).save(original) + session.commit() + with Session(db_engine) as session: + reloaded = EpcPostgresRepository(session).get(epc_property_id) + + # Assert — the measured rafter thickness survives, deep-equal. + assert reloaded == original