Model/backend/documents_parser/tests
Khalim Conn-Kowlessar 36d4bf8750 Slice S0380.172: Heat-network heat-source-eff CO2/PE factor scaling
Closes the CO2 / PE residuals for CH1 (boiler community heating, SAP
code 301) and CH3 (HP community heating, SAP code 304) via SAP 10.2
Table 4a (PDF p.164) heat-network heat-source efficiency:

  "Boilers (RdSAP)"     → 80%   → code 301
  "Heat pump (RdSAP)"   → 300%  → code 304

Spec block 13a (PDF p.153) (467) "PE associated with heat source 2"
= [(307b)+(310b)] × 100 / (467b) — i.e. fuel input = network_input ×
100 / heat_source_eff before applying Table 12 PE factor. Block 12b
(367) mirrors for CO2. The cascade meters network_input directly
(eff = 1/DLF for the cost path via Table 12 heat-network rate), so
PE / CO2 factors are scaled by 1/heat_source_eff at lookup time —
mathematically equivalent to spec's (network_input / eff) × factor.

Three changes:

1. New `_HEAT_NETWORK_HEAT_SOURCE_EFFICIENCY: Final[dict[int, float]]`
   keyed on SAP code: 301 → 0.80, 304 → 3.00. SAP 302 (CHP+boilers)
   is omitted — the 35%/65% split + displaced-electricity credit per
   spec block 13b (464)/(466)/(364)/(366) needs the .171 follow-up.

2. New `_heat_network_heat_source_efficiency_scaling(main)` helper
   returning 1.0 for non-heat-network mains + SAP 302, and
   1/heat_source_eff for SAP 301 / 304.

3. Wired into `_main_heating_co2_factor_kg_per_kwh` and
   `_main_heating_primary_factor` non-electric branches (heat
   networks are non-electric per `_is_electric_main`). Both functions
   return `Table_12_factor × scaling` so the cascade's
   `network_input × scaled_factor` lands on the spec
   `(network_input / eff) × Table_12_factor`.

Closures vs pre-S0380.172 residuals (heating-systems corpus block 11b):

  variant            ΔCO2          ΔPE        notes
  CH1 (Boilers/Gas)  -787→-126    -3827→-967  ~75-84% closure
  CH2 (CHP/Gas)      unchanged     unchanged   excluded — SAP 302
  CH3 (HP/Elec)      +1614→+473  +11879→+1749 ~71-85% closure
  CH4 (CHP/Oil)      unchanged     unchanged   excluded — SAP 302
  CH6 (CHP/Coal)     unchanged     unchanged   excluded — SAP 302

Cost + SAP unchanged on all 5 (heat-network rate × network_input via
Table 12 is correct regardless of heat-source efficiency).

Residual CH1 / CH3 gap drivers (follow-up scope):
- WHC=901 HW path: cascade reads cert-lodged "Mains gas" as HW fuel
  on community-heating certs; should fall through to main fuel for
  the heat-network so the scaling applies on HW side too.
- Elmhurst 0.8523 multiplier on heat-network energy column (worksheet
  (467) energy = spec_formula × 0.8523 uniformly across non-CHP
  heat-network rows; mechanism not yet identified — spec divergence
  candidate for SAP_CALCULATOR.md §8).

Cohort no-regression verified: 9 ASHP + 38 cohort-2 golden fixtures
pass unchanged; the 41-variant heating-systems corpus has identical
residuals for non-heat-network certs. The 2 closed CH variants are
re-pinned at their new sub-1000 magnitudes.

Test baseline at HEAD: 926 pass + 1 skipped (was 926 + 1 at
predecessor a4b5f4e7; pin updates net to 0). Pyright net-zero on
affected files (cert_to_inputs.py, test_heating_systems_corpus.py):
32 → 32.

Per [[feedback-spec-citation-in-commits]] the dispatch table cites
SAP 10.2 Table 4a (PDF p.164) verbatim row labels.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-02 11:44:06 +00:00
..
fixtures Slice S0380.52: cert 000565 Elmhurst-only mapper-driven cascade pin + glazing-label coverage 2026-05-28 22:03:52 +00:00
__init__.py Map to RdSapSiteNotes from site notes JSON 🟥 2026-04-16 13:54:03 +00:00
test_elmhurst_end_to_end.py Slice S0380.17: map Elmhurst §11 glazing-type labels to SAP10 codes 2026-05-27 23:05:52 +00:00
test_elmhurst_extractor.py extract window frame details from elmhurst site notes 🟥 2026-04-27 15:50:25 +00:00
test_end_to_end.py P6.1 follow-on: unbox BuildingPartIdentifier at backend boundaries 2026-05-20 09:58:23 +00:00
test_extractor.py Handle wall thickness "Unmeasurable" 🟩 2026-04-30 16:41:16 +00:00
test_heating_systems_corpus.py Slice S0380.172: Heat-network heat-source-eff CO2/PE factor scaling 2026-06-02 11:44:06 +00:00
test_pdf.py rename example site notes to PasHub_ and add Elmhurst example 2026-04-24 13:01:51 +00:00
test_summary_pdf_mapper_chain.py Slice S0380.143: RdSAP 10 §10.11 Table 29 — derive cylinder insulation defaults from construction age band when §15.1 lodges "No Access" 2026-05-31 21:03:10 +00:00