The heating-donor display synthesis reads donor.epc.main_heating, which has no
dataclass default — so a partial object.__new__ EpcPropertyData must set it.
test_validation's _comparable builder didn't, failing the two leave-one-out
scorer tests in CI (the full epc_prediction suite wasn't run pre-push).
main_heating_controls / sap_ventilation default to None via class attributes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add _apply_ventilation_mode: set the predicted mechanical_ventilation_kind to
the recency/geo-weighted cohort mode (mirrors _apply_glazing_mode — MEV/MVHR is
a new-build/retrofit feature clustering by era + street). Only the kind moves;
the template's sheltered_sides etc. stay. Natural cohorts mode to None and stay
natural (§2 default), so this only moves genuine MEV/MVHR neighbourhoods.
Display-only for the calc gate: component-accuracy (26) + corpus (6) + e2e (1)
all green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prediction never synthesises ventilation — it keeps the size-template's
sap_ventilation, so a predicted dwelling in an MEV/MVHR neighbourhood is scored
+ displayed as natural (predicted property 721167 follow-up). Mode the
mechanical_ventilation_kind across the cohort like glazing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_apply_heating_donor now also deepcopies the donor's main_heating and
main_heating_controls EnergyElements alongside its calc sap_heating cluster, so
the building-passport heating rows are coherent with the donated system and a
control row the size-template lacked (but the donor lodges) is populated. Fixes
'Heating Control: Unknown' on predicted properties (e.g. 721167). Display-only:
component-accuracy gate + corpus harness unchanged (26/6 green).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_apply_heating_donor copies the donor's calc sap_heating but leaves the
display rows (main_heating, main_heating_controls) on the structural template
— incoherent, and 'Heating Control: Unknown' when the template lodged no
control (predicted property 721167, ADR-0029 follow-up).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Both passed no sap_ventilation= → EpcPropertyData default None, dropping the
whole §2 block so MEV/MVHR certs scored as natural. Mirror 21.0.1's block for
the only fields each schema lodges: mechanical_ventilation_kind (§2 MV-kind
dispatch) + sheltered_sides (§S5, from built_form). Neither schema lodges the
fan/flue/vent counts (RdSAP Table-5 age defaults), so those stay unset.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
19.0 + 21.0.0 pass no sap_ventilation= at all → EpcPropertyData default None,
dropping the entire §2 block (sheltered_sides + mechanical_ventilation_kind).
Extend the MVHR mapper test to both and add a sheltered_sides regression,
mirroring 21.0.1 (remaining ADR-0037 ventilation follow-up).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Full-SAP certs mapped property_type=None, so the hard cohort filter silently
excluded them as comparables. Correctly typing them admits real lodged EPCs as
donors — a ground-truth-method change (cf #1245). Net over the n=36 fixture: 16
components better, 4 worse, 6 unchanged; gains concentrated in the physical
characteristics full-SAP certs measure (window_count 3.83->1.69, building_parts,
total_window_area, floor_construction, construction_age_band, glazing, walls).
The 4 that fell are new-build-vs-old-stock service mismatch on 1-2 targets each
(heating/water fuel, cylinder insulation) + floor_area. Tighten 16, loosen 4.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17.1/18.0/20.0.0 built SapVentilation(sheltered_sides=…) and dropped the cert's
mechanical_ventilation, mis-scoring MEV/MVHR dwellings as natural. Mirror 21.0.1's
_api_mechanical_ventilation_kind. Natural certs (code 0/5 → None) unchanged
(corpus 73.3%/0.774, mapper corpus green, 726605 SAP 68.058 unchanged).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Captures the calc-facing ventilation-type gap (older RdSAP mappers drop
mechanical_ventilation_kind), the FE-side Main Fuel display, the sweep survivor
clusters, and the predicted-property display path — all separate from ADR-0037.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Captures the grill-with-docs decisions for the full-SAP-17.1 mapper completion:
rebaseline-to-10.2 (restores Rebaselining trigger (a)), calc-affecting fields
coupled with the sap_version flip, and growing Elmhurst-anchored validation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Terraform computes SOLAR_MIN_REQUEST_INTERVAL_SECONDS = N / (0.8 * 600 / 60)
from var.maximum_concurrency (=4.0s at N=32) so the fleet width has one source
of truth and the per-container Solar pacing tracks it automatically.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>