From 600684f5dfaaedf2a08e7e85b40fd02b96538072 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Sat, 20 Jun 2026 14:09:21 +0000 Subject: [PATCH] fix(uvalues): apply metal-frame U 1.6 for 2022-or-later windows (RdSAP 10 Table 24, PDF p.51) Table 24 "Double or triple glazed, 2022 or later" row gives U = 1.4 for PVC/wooden frames and 1.6 for metal frames. `u_window` returned 1.4 for both, ignoring the metal-frame variant and under-counting metal-frame heat loss on post-2022 windows. The 2002-2021 and pre-2002 rows already split PVC/metal correctly; this aligns the 2022+ row. Spec-pinned in test_u_window_post_2022_metal_returns_table24_1_6_not_pvc_1_4. pyright not installed in this container. Co-Authored-By: Claude Opus 4.8 (1M context) --- domain/sap10_ml/rdsap_uvalues.py | 3 ++- domain/sap10_ml/tests/test_rdsap_uvalues.py | 12 ++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/domain/sap10_ml/rdsap_uvalues.py b/domain/sap10_ml/rdsap_uvalues.py index 6b1e35fc..b4ab5de3 100644 --- a/domain/sap10_ml/rdsap_uvalues.py +++ b/domain/sap10_ml/rdsap_uvalues.py @@ -1419,7 +1419,8 @@ def u_window( # double/triple glazing — period bands. if installed_year is not None and installed_year >= 2022: - return 1.4 + # Table 24 "2022 or later" row: PVC/wood 1.4, metal 1.6. + return 1.6 if metal else 1.4 if installed_year is not None and installed_year >= 2002: return 2.2 if metal else 2.0 # pre-2002 double/triple default to 12mm gap row. diff --git a/domain/sap10_ml/tests/test_rdsap_uvalues.py b/domain/sap10_ml/tests/test_rdsap_uvalues.py index 77de58eb..522ccd52 100644 --- a/domain/sap10_ml/tests/test_rdsap_uvalues.py +++ b/domain/sap10_ml/tests/test_rdsap_uvalues.py @@ -1748,6 +1748,18 @@ def test_u_window_post_2022_pvc_returns_low_table24_value() -> None: assert result == pytest.approx(1.4, abs=0.001) +def test_u_window_post_2022_metal_returns_table24_1_6_not_pvc_1_4() -> None: + # Arrange — Table 24 "2022 or later" row (PDF p.51): PVC/wooden frame + # 1.4, METAL frame 1.6. The metal frame variant was previously ignored + # (1.4 returned for both), under-counting metal-frame heat loss. + + # Act + result = u_window(installed_year=2023, glazing_type="double", frame_type="metal") + + # Assert + assert result == pytest.approx(1.6, abs=0.001) + + def test_u_window_falls_back_to_mid_range_when_unknown() -> None: # Arrange — nothing known.