From 8520a52ee9ac257b7681af353a1bef55c7887e30 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Sat, 23 May 2026 23:04:23 +0000 Subject: [PATCH] =?UTF-8?q?Slice=2025c:=20000477=20=C2=A74/=C2=A75/=C2=A76?= =?UTF-8?q?=20closure=20=E2=80=94=20Table=203c=20(p.162)=20M+L=20lower=20b?= =?UTF-8?q?ound?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed a single-character spec adherence bug: SAP10.2 Table 3c (p.162) specifies the M+L profile's DVF lower bound as `V_d,m < 100.2`, not `< 100.0`. The 0.2 L/day window matters when V_d,m sits between 100.0 and 100.2 — exactly where 000477's May lodgement lands (100.16 L/day). For V_d,m = 100.16: Spec: DVF = 0 → (61) = E × r1 × fu = 134.84 × 0.015 × 1.0 = 2.0225 ✓ Buggy: DVF = 100.2 - 100.16 = 0.04 → (61) = 2.0233 (off by 0.0008) The cascade through the missing 0.0008 W on May LINE_61 propagated to LINE_62/64/65 and then §5 LINE_72/73 + §6 LINE_84 — clearing one constant unblocks the entire 000477 §4-§6 cluster. Per-fixture cluster status (was/now): §3 24/24 → 24/24 §4 46/54 → 53/54 (only 000487 LINE_65 remains) §5 50/54 → 52/54 (only 000487 LINE_72/73) §6 10/12 → 11/12 (only 000487 LINE_84) All remaining cascade failures cluster on 000487 (slice 25d — derive LINE_64A electric-shower kWh from cert per Appendix J step 8) plus §7 LINE_92/93 marginal residuals on 4 fixtures (precision artefact). Scoreboard: section_cascade_pins: 286 → 293 PASS (+7) e2e SapResult: 32 → 32 PASS (still cascade-blocked by 000487 LINE_65 + downstream §8-§12 pins not yet asserted) Co-Authored-By: Claude Opus 4.7 --- docs/sap-spec/HANDOVER_NEXT.md | 16 +++++++--------- .../sap/worksheet/tests/test_water_heating.py | 7 +++++-- .../src/domain/sap/worksheet/water_heating.py | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/docs/sap-spec/HANDOVER_NEXT.md b/docs/sap-spec/HANDOVER_NEXT.md index 2efe1bc2..ba6eb72c 100644 --- a/docs/sap-spec/HANDOVER_NEXT.md +++ b/docs/sap-spec/HANDOVER_NEXT.md @@ -133,15 +133,12 @@ Two test files contain the strict pins: Total: **169 PASS / 83 FAIL** across the strict pins. 4 of 6 fixtures fully close §1+§2+§4. 000487 is the worst (RR fixture defect propagates everywhere). -(Post-slice-25b: section_cascade_pins 286 PASS / 26 FAIL, e2e SapResult -32 PASS / 40 FAIL. §3 fully closes for all 6 fixtures (24/24). §4 closes -8 of 9 for 000487 — only LINE_65 (heat gains from WH) still fails -because the §4 cascade doesn't yet derive (64a) electric-shower kWh -from the cert (Appendix J step 8). Remaining cascade failures: §4 on -000477 (combi loss precision, slice 25c) + §4 LINE_65 on 000487 -(electric shower derivation), §5/§6 LINE_72/73/84 on 000477+487 -(cascade from §4), §7 LINE_92/93 marginal on 000474/477/480/490 -(precision artefact), §7 on 000487 (cascade from §4 LINE_65).) +(Post-slice-25c: section_cascade_pins 293 PASS / 19 FAIL, e2e SapResult +32 PASS / 40 FAIL. §3 closes 24/24. §4 closes 53/54 (only 000487 +LINE_65 remains — Appendix J step 8 electric-shower kWh derivation, +slice 25d). §5 52/54, §6 11/12 — only 000487 cascade. 000477's §4 +combi-loss cluster was closed by fixing the SAP10.2 Table 3c (p.162) +M+L lower bound: my DVF used `V < 100.0` where spec says `V < 100.2`.) ### B.2 SapResult pin matrix (post-slice-22/23) @@ -202,6 +199,7 @@ fixture | section §4 pin status ### B.5 Recent slices (in reverse order — newest first) ``` +Slice 25c: 000477 §4/§5/§6 closure — SAP10.2 Table 3c (p.162) M+L lower bound 100.0 → 100.2 Slice 25b: 000487 §4 closure (7/8) — has_electric_shower + mixer/electric counts on SapHeating, Appendix J step 2a fix Slice 25a: 000487 §3 closure — detailed RR + gable_wall_external + Ext1 alt U=1.9 + §3.8 max-floor roof + half-up rounding Slice 26c: §7 mean internal temp cascade pin (60 cases, 44 PASS) — LINE_85..94 diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py b/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py index 1c9424e6..fd5729aa 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py +++ b/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py @@ -555,10 +555,13 @@ def test_combi_loss_table_3c_two_profile_matches_elmhurst_000477_lodged_line_61( @pytest.mark.parametrize( "profile_pair, daily_hot_water_l_per_day, expected_dvf", [ - # M+L: 0 for V<100, 100.2-V for V∈[100, 199.8], -99.6 for V>199.8. + # M+L: 0 for V<100.2, 100.2-V for V∈[100.2, 199.8], -99.6 for V>199.8. + # Per SAP10.2 Table 3c (p.162): the lower bound is 100.2 L/day, + # not 100.0 — so V=100.16 (Elmhurst 000477 May) routes to DVF=0. ("M+L", 50.0, 0.0), ("M+L", 99.99, 0.0), - ("M+L", 100.0, 0.2), + ("M+L", 100.16, 0.0), + ("M+L", 100.3, -0.1), ("M+L", 150.0, -49.8), ("M+L", 199.8, -99.6), ("M+L", 200.0, -99.6), diff --git a/packages/domain/src/domain/sap/worksheet/water_heating.py b/packages/domain/src/domain/sap/worksheet/water_heating.py index 3dc380b6..dac1b18f 100644 --- a/packages/domain/src/domain/sap/worksheet/water_heating.py +++ b/packages/domain/src/domain/sap/worksheet/water_heating.py @@ -338,7 +338,7 @@ def combi_loss_monthly_kwh_table_3b_row_1_instantaneous( ) -_DVF_M_AND_L_LOWER_V_L_PER_DAY: Final[float] = 100.0 +_DVF_M_AND_L_LOWER_V_L_PER_DAY: Final[float] = 100.2 _DVF_M_AND_L_UPPER_V_L_PER_DAY: Final[float] = 199.8 _DVF_M_AND_L_UPPER_CLAMP: Final[float] = -99.6 _DVF_M_AND_S_LOWER_V_L_PER_DAY: Final[float] = 36.0