Model/domain
Khalim Conn-Kowlessar 45036e821b Slice S0380.174: §4 storage + primary loss for community heating
SAP 10.2 §4 "Heat networks" (PDF p.17 line 1482):

    "Primary circuit loss for insulated pipework and cylinderstat
     should be included (see Table 3)."

SAP 10.2 Table 2b note b (PDF p.159) verbatim:

    "Multiply Temperature Factor by 0.9 if there is separate time
     control of domestic hot water (boiler systems, warm air systems
     and heat pump systems)."

The Table 2b note b ×0.9 multiplier is restricted to "boiler / warm
air / heat pump systems" — community heating is omitted from that
verbatim list. Pre-slice the cascade applied the ×0.9 reduction
unconditionally when DHW was separately timed, AND omitted the Table
3 primary-loss path for heat-network mains entirely. Combined the
two gaps under-counted (62)m HW total demand by ~320 kWh/yr for
heating-systems corpus 001431 community heating 1 (8164 + 0 vs
448.74 + 273.90 spec losses).

Three changes:

1. New `_HEAT_NETWORK_PIPEWORK_INSULATION_FRACTION = 1.0` constant.
   `_primary_loss_override` selects this for heat-network mains
   instead of the RdSAP §3 age-band default, per the spec's literal
   "insulated pipework" + back-solve from worksheet (59) Jan = 23.26
   = 31 × 14 × (0.0091×3 + 0.0263).

2. Extended `_primary_loss_applies` with a new branch: heat-network
   main + WHC ∈ {901, 902, 914} + cylinder present → primary loss
   applies.

3. New `_table_2b_note_b_multiplier_applies(epc, main)` predicate
   that gates the ×0.9 storage-loss reduction on the spec's verbatim
   system-type list, returning False for heat-network mains. The
   primary-loss `_separately_timed_dhw` continues to return True for
   community heating (Table 3's "separately timed" row is system-
   type-agnostic and gives h=3 all year).

Closures (heating-systems corpus 001431):
  CH1 HW kWh 3391.90 → 3854.12 (= ws 3854.1175, abs Δ < 1e-3)
  CH1 HW cost £143.82 → £163.41 (= ws £163.41, EXACT)
  CH1 (65)m heat gains 793.51 → 1221.62 (= ws 1221.62, EXACT)
  CH2/CH3/CH4/CH6 same shape — HW path closes against ws (310).

§4 fix is spec-correct on all 5 CH variants. The closure surfaces a
separate §7 MIT (92)m over-count of +0.46 K (cascade Jan = 17.22 vs
ws 16.76) that the pre-slice (65)m gain under-count was masking. Per
[[feedback-software-no-special-handling]] apply the spec-correct
fix uniformly; new pinned residuals reflect the exposed MIT gap.

New residuals (vs pre-slice):
  CH1   ΔSAP -0.5273 → -1.0572  ΔPE -9.15  → +408.67
  CH2   ΔSAP -0.0076 → -0.4187  ΔPE +1506  → +1779
  CH3   ΔSAP -0.5273 → -1.0572  ΔPE -387.03 → -239.03
  CH4   ΔSAP -0.0076 → -0.4187  ΔPE +494.61 → +767.13
  CH6   ΔSAP -8.0295 → -8.4406  ΔPE +7864.60 → +8137.11

927 pass + 0 fail (+1 new test). No regressions on the other 36
corpus variants — the gate is narrow on `_is_heat_network_main`.
Pyright net-zero (43 → 43) on cert_to_inputs.py + tests.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-04 15:40:26 +00:00
..
addresses standardist Address 2026-05-22 10:13:32 +00:00
data_transformation moved classifier data transformation to an easy one 2026-06-01 14:53:34 +00:00
epc Remove EPC and asset_list changes unrelated to SAL handler 2026-06-01 16:39:09 +00:00
geospatial feat(geospatial): GeospatialRepo — OS Open-UPRN coordinate lookup (#1131) 2026-06-01 16:28:48 +00:00
property feat(property): Property aggregate + PropertyRepository (#1132) 2026-06-01 16:28:48 +00:00
property_baseline refactor(property-baseline): rename baseline → property_baseline aggregate (PR #1139 review) 2026-06-01 16:28:48 +00:00
sap10_calculator Slice S0380.174: §4 storage + primary loss for community heating 2026-06-04 15:40:26 +00:00
sap10_ml Slice S0380.109: Solid brick + insulation via §5.7 Table 13 + §5.8 Table 14 (RdSAP 10) 2026-05-30 18:10:33 +00:00
tasks added postcode splitter rewrite to ddd 2026-05-19 16:35:09 +00:00
postcode.py get rid of comments 2026-05-20 13:21:11 +00:00