Model/datatypes/epc
Khalim Conn-Kowlessar 2adff08210 Slice S0380.75: Wire Appendix H orchestrator into cascade; cert 000565 HW +272 → −69
Per SAP 10.2 §4 line (64)m: `(64)m = max(0, (62)m + (63a)m + (63b)m
+ (63c)m + (63d)m)` where (63c)m is the solar HW credit lodged as a
negative quantity. The cascade hardcoded (63c)m = 0 since S0380.66
when the Appendix H orchestrator landed without integration, pending
the 1.81× over-count resolution (closed in S0380.74).

This slice plumbs the orchestrator into `water_heating_from_cert`
via a new `solar_water_heating_monthly_kwh_override` parameter, and
adds `_solar_hw_monthly_override` in cert_to_inputs.py that drives
the orchestrator from RdSAP 10 §10.11 Table 29 defaults +
cert-lodged collector geometry on Elmhurst Summary §16.0.

RdSAP 10 §10.11 Table 29 row "Solar panel" (p.58, verbatim):
  "If solar panel present, the parameters for the calculation not
   provided in the RdSAP data set are:
   - panel aperture area 3 m²
   - flat panel, η₀ = 0.80, a₁ = 4.0, a₂ = 0.01
   - facing South, pitch 30°, modest overshading
   - …
   - pump for solar-heated water is electric (75 kWh/year)
   - showers are both electric and non-electric"

Lodged collector orientation / pitch / overshading on the Summary
§16.0 ("Are details known? Yes" branch) override South / 30° /
Modest. Aperture, η₀, a₁, a₂, IAM stay at Table 29 defaults — the
deeper thermal parameter lodgement (P960 worksheet) isn't yet in
the Summary extractor surface.

For (H17)m to include storage + primary + combi losses, the cascade
runs a `demand_pass` call without solar (gets (62)m) before sizing
the solar credit. The final call then uses all overrides.

Files:
- datatypes/epc/surveys/elmhurst_site_notes.py: Renewables gains
  `solar_hw_collector_orientation` / `_pitch_deg` / `_overshading`
  optional fields.
- datatypes/epc/domain/epc_property_data.py: same three fields
  added at the end of the dataclass.
- datatypes/epc/domain/mapper.py: from_elmhurst_site_notes
  propagates the three new fields.
- backend/documents_parser/elmhurst_extractor.py: §16.0 section
  parsing reads "Collector orientation" / "Collector elevation" /
  "Overshading" rows; `_parse_solar_pitch_deg` strips the degree
  glyph.
- domain/sap10_calculator/worksheet/water_heating.py: new
  `solar_water_heating_monthly_kwh_override` param on
  `water_heating_from_cert`; threaded into `output_from_water_
  heater_monthly_kwh(solar_monthly_kwh=...)`.
- domain/sap10_calculator/rdsap/cert_to_inputs.py: Table 29
  constants + `_solar_hw_monthly_override` helper +
  `_orientation_from_summary_string` mapper. Added the demand_pass
  intermediate call so (H17)m sees the full (62)m. Negates the
  orchestrator output at the boundary (spec convention: heat
  displaced from boiler is negative on line (63c)m).

Cert 000565 cascade pin shifts:
- hot_water_kwh_per_yr: +271.84 → −68.96 (4× closer)
- sap_score_continuous: +0.6334 → +0.7732 (drift downstream of HW)
- ecf: −0.0643 → −0.0784 (drift)
- total_fuel_cost: −56.08 → −68.36 (drift)
- co2: −19.77 → −22.66 (drift)
- sap_score (int): 29 EXACT (unchanged)
- space_heating / main_heating_fuel / lighting / pumps_fans:
  unchanged

The remaining −69 kWh HW residual is the gap between Table 29
defaults (H12 = 75 L separate tank) and cert 000565's lodged H12 =
53 L + combined cylinder 160 L. Closing this requires extracting
solar storage volume + combined-cylinder routing from the cert (P960
worksheet block lodges these explicitly; Summary doesn't). That's
the follow-on slice.

Test baseline: 547 pass + 9 expected `test_sap_result_pin[000565-*]`
fails preserved. Cohort-2 + ASHP cohort + all golden fixtures
untouched (no certs other than 000565 lodge `solar_water_heating =
True`).

Pyright net-zero on touched files (68 errors at baseline = 68 errors
post-change).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-01 16:28:47 +00:00
..
domain Slice S0380.75: Wire Appendix H orchestrator into cascade; cert 000565 HW +272 → −69 2026-06-01 16:28:47 +00:00
loaders demo generated for use in address2uprn 2026-05-08 14:48:15 +00:00
schema Slice S0380.48: surface real-API pv_batteries[].battery_capacity (5 kWh) 2026-06-01 16:28:47 +00:00
search bolstering testing 2026-04-28 13:46:09 +00:00
surveys Slice S0380.75: Wire Appendix H orchestrator into cascade; cert 000565 HW +272 → −69 2026-06-01 16:28:47 +00:00
__init__.py testing out rebaselining 2026-02-12 22:25:03 +00:00
construction_age_band.py testing out rebaselining 2026-02-12 22:25:03 +00:00
efficiency.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
floor.py preparing partiy class 2026-02-05 08:54:27 +00:00
fuel.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
heating_controls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
hotwater.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
main_heating.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
property_type_built_form.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
roof.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
walls.py beginning to assembly the parity class 2026-02-04 18:34:59 +00:00
windows.py testing out rebaselining 2026-02-12 22:25:03 +00:00