A dwelling's heating is one conceptual system, but its fields are scattered across EpcPropertyData (a gov-API schema mirror): the cluster on sap_heating, the electricity tariff on sap_energy_source.meter_type, hot-water flags loose at top level. Three places synthesise a heating system — Measure Options, Landlord Overrides, EPC Prediction's donor — and each hand-copied a different ad-hoc subset. The override and donor both dropped meter_type, so an electric-storage system landed on the template's single-rate meter and billed overnight heat at the peak rate: property 713406 scored SAP 13 (G) vs ~50 (E), inflating the HHRSH measure to +45.8 and overshooting the plan to band A. Establish a single Coherent Heating System boundary (CONTEXT.md) that every synthesiser must cover, with a source-appropriate fill policy (ADR-0035): - Override overlay *completes* the partial system the landlord named. Companion fields are now DERIVED from the SAP code, not hand-attached per archetype: the off-peak meter from the calculator's single off-peak classification (new OFF_PEAK_IMPLYING_HEATING_CODES = SAP §12 Rules 1-2), and an unobserved storage charge control defaults to the conservative manual control (Table 4e 2401). So adding a heating archetype is just adding its code — companions can't be forgotten. A contract test guards it (every off-peak code drags a Dual meter). - Prediction's heating donor now *carries* the donor's meter_type alongside its sap_heating cluster — the donor is already coherent. Coherence is a synthesis-time obligation only; the calculator still scores a real lodged cert exactly as lodged. Verified on 713406: baseline 13 -> 47.8 (E), matching its recorded rating; the phantom HHRSH recommendation is gone and the plan no longer overshoots to A. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3.5 KiB
Coherent Heating System is owned by the synthesiser, not the calculator
Status
accepted
Context
A dwelling's heating is one conceptual system, but its fields are physically
scattered across EpcPropertyData because that type mirrors the gov-API / RdSAP
schema: the main cluster lives on sap_heating, the electricity tariff on
sap_energy_source.meter_type, and hot-water flags (has_hot_water_cylinder,
solar_water_heating) on loose top-level fields.
Three places synthesise a heating system — a Measure Option (HHRSH/ASHP), a
Landlord Override, and EPC Prediction's heating donor — and each was hand-copying
a different ad-hoc subset of those fields. The override and the donor both
omitted meter_type. Property 713406 (a predicted property whose landlord
override set "Electric storage heaters") landed on the oil structural template's
single-rate meter, so its overnight storage heat billed at the peak electricity
rate: the calculator scored it SAP 13 (G) instead of ~50 (E), which then
inflated the HHRSH measure to +45.8 SAP and pushed the plan to band A.
Decision
Treat "a heating system" as one named boundary (a Coherent Heating System — see CONTEXT.md). Whoever synthesises a heating system owns covering the whole boundary, with a fill policy suited to its source:
- Measure → set a designed end-state (already did).
- Landlord Override → complete the partial system the landlord named.
Companion fields are derived from the SAP code, not hand-attached per
archetype: the off-peak meter from the calculator's single off-peak
classification (
OFF_PEAK_IMPLYING_HEATING_CODES, SAP §12 Rules 1-2), and — where a field has no logical pairing — a conservative default (storage charge control → manual, SAP Table 4e 2401, the lowest-SAP storage control). So adding a heating archetype is just adding its code; coherent companions fall out and cannot be forgotten. - EPC Prediction donor → carry a real neighbour's whole coherent set
(including its
meter_type), since the donor is already internally coherent.
Coherence is a synthesis-time obligation, never a calculator normalisation.
A real lodged cert is scored exactly as lodged — the calculator must not "fix" a
genuinely single-rate storage dwelling (its existing Unknown-meter inference is
a separate, spec-faithful net for certs that lodged Unknown, and does not fire
on an explicit meter). A contract test guards the override path: every off-peak
code the archetype map can emit must drag a Dual meter.
Considered Options
- Reify a
HeatingSystemvalue object all three produce/consume — rejected: overlapsHeatingOverlayand is a large, risky restructure for the value. - A global coherence pass over the assembled effective EPC — rejected: it would corrupt real lodged certs (force storage→dual on a genuine single-rate lodgement). Coherence must be scoped to synthesis points.
- Set
meter_type="Unknown"and lean on the calculator's storage inference — rejected as the primary mechanism: an explicitDualis self-contained, matches the measure overlay, carries display value, and does not depend on a repo extension that could later be tightened toward spec.
This amends ADR-0029 (the heating donor now carries the meter) and extends ADR-0032 (the override overlay derives coherent companions).