diff --git a/domain/sap10_calculator/docs/HANDOVER_MAPPER_BUGS.md b/domain/sap10_calculator/docs/HANDOVER_MAPPER_BUGS.md index 24d8a4d5..7237497e 100644 --- a/domain/sap10_calculator/docs/HANDOVER_MAPPER_BUGS.md +++ b/domain/sap10_calculator/docs/HANDOVER_MAPPER_BUGS.md @@ -6,13 +6,14 @@ state after closing the 0240 investigation and fixing the first of several API-mapper/cascade bugs the audit surfaced. - **Branch:** `feature/per-cert-mapper-validation` -- **HEAD:** `08dd0b4c` (S0380.212). Confirm with `git rev-parse HEAD`. -- **Baseline:** `2384 passed, 1 skipped, 0 failed` (AGENT_GUIDE §4 suite command). +- **HEAD:** `ee484d9f` (S0380.213). Confirm with `git rev-parse HEAD`. +- **Baseline:** `2386 passed, 1 skipped, 0 failed` (AGENT_GUIDE §4 suite command). ALSO run `domain/sap10_ml/tests/` when touching `rdsap_uvalues.py` — 2 PRE-EXISTING stone-formula failures there, see Thread 1. -- **Next slice number:** **S0380.213**. -- **Open:** Thread 2 *cost* tail only — 9390 SAP +4 (heat-network cost missing - 1/heat_source_eff scaling). CO2/PE collision FIXED (S0380.212). Threads 1 + 3 **CLOSED**. +- **Next slice number:** **S0380.214**. +- **Open:** Thread 2 *demand* tail only — 9390 ~7% demand over-count (SAP -2, PE 220 vs + 205) = heat-source-efficiency-default / fabric residual. CO2/PE collision (S0380.212) + + standing charge (S0380.213) FIXED. Threads 1 + 3 **CLOSED**. --- @@ -25,6 +26,7 @@ API-mapper/cascade bugs the audit surfaced. | **S0380.210** | **CLOSED cert 0390** (Thread 3). Cavity wall "as built, **partial** insulation (assumed)" (type 4) was mis-routed to the Table 6 "Filled cavity" row (band F 0.40) → should be "Cavity as built" (band F 1.0). New `_cavity_described_as_filled` in `rdsap_uvalues.py` excludes "partial insulation" from the filled trigger (keeps "insulated (assumed)" → filled). SAP +7 → +0, PE −27.97 → +0.53, CO2 −2.71 → −0.12. Mirrors S0380.209 on the cavity path. | | **S0380.211** | **CLOSED Thread 1 (roof).** 0240 Ext1 vaulted (code 5) NI roof returned 0.68 (§5.11.4 50 mm) → should be Table 18 col (1) age-band (band J 0.16), matching 33 cohort-2 `ND` vaulted roofs. New `u_roof(is_sloping_ceiling=...)` flag threaded from heat_transmission (codes 5/8). 0240 PE +5.50 → +1.52, CO2 +0.28 → +0.07 (SAP 72). Also corrected the S0380.210 cavity unit test in `domain/sap10_ml/tests/` (suite-command gap — see Thread 1). | | **S0380.212** | **Thread 2 CO2/PE collision FIXED.** EPC fuel 20 = "mains gas (community)" collided with Table-12 biomass code 20 → community CO2 6.4× low. New `_heat_network_factor_fuel_code` translates 20→51 for heat-network mains only (5 sites: SH+HW CO2/PE/price). 9390 CO2 0.44→3.03 t (lodged 2.8), PE 204→220. Case-14-validated ((367) 0.2100 / (467) 1.1300). Cost +4 tail open. | +| **S0380.213** | **Thread 2 cost +4 FIXED** via the heat-network standing charge. API community fuel 20 isn't a Table-32 gas code → `_is_gas_code` False → £0 standing (vs SAP 10.2 Table 12 note (l) £120; case 14 `(351)`=£120). New `_heat_network_standing_charge_gbp` (£120 full / £60 DHW-only, §C3.2) REPLACES the fuel standing for heat-network mains (no double-count; CH corpus stays £120). 9390 SAP +4 → -2 (exposes a ~7% demand over-count — follow-up). | Both also carry a memory: [[project_case7_combi_exonerated]], [[project_as_built_insulated_assumed_bug]]. @@ -125,12 +127,22 @@ the API-only register residual; 9390 is unpinned, retired P2.2 per ADR-0010 §10 Summary path uses code 1 (no collision) → CH1-6 corpus untouched. Locked by 2 unit tests in `test_cert_to_inputs.py`. -**STILL OPEN — 9390 SAP +4 (separate cost-scaling gap):** the heat-network cost path -(`_fuel_cost_gbp_per_kwh`, cert_to_inputs.py ~L1888) does NOT apply the -`1/heat_source_eff` (1/0.80) scaling the CO2/PE paths do, so community fuel cost -under-counts → SAP over-reads. Validate the fix against case 14's **10b fuel-cost block** -(+ Table 32 note (l) £120 community standing charge). Run the heating-systems corpus after -(touchy area, [[project_heating_systems_corpus]]). +**Cost +4 — FIXED (S0380.213), via the standing charge (NOT cost scaling).** The earlier +"missing 1/heat_source_eff cost scaling" hypothesis was WRONG: case 14's 10b block shows +the heat price (`(340)`/`(307)` = 4.24 p/kWh) is applied to delivered heat, NOT scaled — +and Table-32 code 51 already = 4.24 p/kWh (the price collision was harmless, 4.23≈4.24). +The real gap was the **£120 heat-network standing charge** (SAP 10.2 Table 12 note (l) + +§C3.2; case 14 `(351)` = £120): the API community fuel (20) isn't a Table-32 gas code so +`_is_gas_code` returned False → £0 standing (the Summary path masks it via code 1). New +`_heat_network_standing_charge_gbp` REPLACES the fuel standing for heat-network mains +(£120 full / £60 DHW-only) — not additive, so the CH corpus (already £120 via the gas +branch) isn't double-counted to £240. 9390 SAP +4 → **-2**. + +**STILL OPEN — 9390 ~7% demand over-count (SAP -2):** the standing fix EXPOSED it — PE 220 +vs lodged 205, CO2 3.03 vs 2.8 all run ~7% high. Likely the heat-source-efficiency default +(`_HEAT_NETWORK_HEAT_SOURCE_EFFICIENCY[301]=0.80`) being too low for 9390's actual scheme, +or a fabric/demand difference. 9390 is API-only (no worksheet) + unpinned, so this is a +low-priority residual; needs a 9390-specific efficiency/fabric investigation. --- @@ -172,7 +184,7 @@ that test. | cert | SAP resid | diagnosis | |---|---|---| | 0390-2954-3640 | ~~+7~~ **+0** | **CLOSED S0380.210** — cavity partial-insulation → as-built row | -| 9390-2722-3520 | +4 (unpinned) | **CO2/PE collision FIXED S0380.212** (CO2 0.44→3.03 t); SAP +4 cost-scaling tail open | +| 9390-2722-3520 | −2 (unpinned) | **CO2/PE collision FIXED S0380.212** + **standing charge S0380.213** (SAP +4→−2); remaining ~7% demand over-count (heat-source-eff default?) | | 0240-0200-5706 | −1 | NOT a bug — unpreserved 2013+ pump; true SAP 72. Roof PE-pin tightened by **S0380.211** (PE +5.50 → +1.52) | | 2130-1033-4050 | +1 | minor fabric precision (multi-part solid-brick wall); low value | | 7536-3827-0600 | +1 | minor fabric precision (multi-bp D/L/F cavity); low value |