The efficient Vaillant aroTHERM plus 5 kW (ADR-0025) now raises SAP even on gas
dwellings, so the Optimiser selects the ASHP bundle far more often -- a deliberate
product shift (user-confirmed). Updated the integration/harness tests:
- ARA multi-measure: ASHP is additive to the kept fabric package -> add to set.
- ARA listed_uprn: is_listed blocks walls AND ASHP (blocks_internal); the gate is
now observable via ASHP (selected unrestricted, blocked listed).
- report three-measures: ASHP + solid-floor displace the fabric stack; assert
their triggers (property_type, main_heating_category / floor).
- console hhr + solid_wall coverage tests: assert the measure is OFFERED as a
candidate (the wiring/eligibility intent), since ASHP now out-competes them in
selection; also assert the optimised package leads with ASHP.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Slice 4 of the lighting generator (ADR-0023): run recommend_lighting in
_candidate_recommendations (no planning gate). Price low_energy_lighting in the
offline catalogue + contingency table (0.26, the legacy rate); the
_GENERATOR_MEASURE_TYPES forcing test enforces both. A run_modelling test pins
the wiring end-to-end (an incandescent-lit dwelling gets the LED upgrade in the
optimised package).
Downstream updates, all because lighting now fires on any cert with non-LED
bulbs: report.py gains the low_energy_lighting trigger (the non-LED counts); the
two golden-cert report tests and the multi-measure integration test now expect
low_energy_lighting alongside the fabric measures (the sample/golden EPCs lodge
low-energy-unknown bulbs); first-run integration seeds a low_energy_lighting
MaterialRow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
format_report_csv emits one comma-safe row per property: the calculator-error
fields (lodged/calculated/Δ/flag), the Plan headline figures (baseline+post
SAP/band, measures, cost+contingency, bill & CO2 savings, valuation %), the
flattened measure triggers, and any captured error — sortable in a spreadsheet
for a large dump.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
format_report_markdown emits: (1) cohort parity stats + a per-property
lodged-vs-calculated table flagging |Δ| > 0.5 (errors shown inline),
(2) Plans + costings (SAP/band jump, cost + contingency, bill & CO2 savings,
valuation uplift), (3) each fired measure with the EPC attributes that
triggered it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
build_property_reports models a dump in order (errors captured per-cert);
parity_report_for aggregates the lodged-vs-calculated SAP across the cohort
into the existing ParityReport (MAE/RMSE/bias/worst-N), excluding certs that
couldn't be mapped or scored. Residual convention is the calculator's own
(predicted - actual), the negative of PropertyReport.sap_error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Section 3 of the report: build_property_report now runs the Modelling stage
and, for every Plan Measure, records the EPC attribute(s) that caused its
generator to fire (MeasureTrigger) — wall_construction/insulation for cavity
fill, roof thickness for loft, floor thickness/construction for floors, the
absent mechanical kind for ventilation. Modelling raises are captured as
plan_error, independent of the calculator-error capture.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Section 1 of the property inspection report: PropertyReport compares the
cert's lodged energy_rating_current to Sap10Calculator's un-rounded SAP and
flags |Δ| > 0.5 (the ADR-0010/0013 shadow-validation design target). A
mapping/scoring raise is captured per-cert as calculator_error, never
propagated, so one bad cert can't abort the sweep.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>