Model/backend/documents_parser
Khalim Conn-Kowlessar a9143d0921 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-05-29 18:37:56 +00:00
..
handler address JTK review comments 2026-04-20 15:11:17 +00:00
tests Slice S0380.64: Elmhurst per-extension wall_construction mappings + strict-raise 2026-05-29 08:57:25 +00:00
__init__.py Map to RdSapSiteNotes from site notes JSON 🟥 2026-04-16 13:54:03 +00:00
db_writer.py include updating epc_property_data to pashub to ara workflow 2026-04-29 09:55:14 +00:00
elmhurst_extractor.py Slice S0380.75: Wire Appendix H orchestrator into cascade; cert 000565 HW +272 → −69 2026-05-29 18:37:56 +00:00
extractor.py Handle wall thickness "Unmeasurable" 🟩 2026-04-30 16:41:16 +00:00
local_runner.py update local runner to work for elmhurst 2026-04-24 14:01:36 +00:00
parser.py load ecmk site notes to db 2026-04-29 11:20:47 +00:00
pdf.py update local runner to work for elmhurst 2026-04-24 14:01:36 +00:00