test(orchestration): re-pin multi-measure plan to the gain-maximising package

The optimiser-package expectation was stale: it predated the optimiser
folding a triggered measure's forced dependency into its candidate gain
(ADR-0016). The run considers ALL measures (considered_measures defaults
to None — no restriction), so once the ASHP bundle became SAP-beneficial
(ADR-0025) the gain-maximising package shifted.

Verified the new package is CORRECT, not a regression: on the test EPC,
cavity-wall insulation earns +2.9 SAP alone but its forced fabric→
ventilation dependency (ADR-0016) drags the wall+ventilation pair to a
NET −1.8 SAP (−0.9 on top of the ASHP package), so the gain-maximising
Optimiser correctly excludes the wall and its forced ventilation. Update
the expected set to {air_source_heat_pump, suspended_floor_insulation,
low_energy_lighting, secondary_heating_removal} and drop the wall/vent-
specific assertions — the forced wall→ventilation edge is covered by
test_measure_dependency / test_optimiser; this integration test keeps its
end-to-end optimise→persist→telescope coverage on the chosen package.

Pre-existing failure (present before this branch's recent commits), outside
the handover regression gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-15 13:46:22 +00:00
parent 4fdc23f83d
commit 077e3a3947

View file

@ -384,29 +384,29 @@ def test_modelling_optimises_and_persists_a_multi_measure_plan(
assert plan.energy_consumption_savings > 0.0
by_type = {rec.type: rec for rec in rec_rows}
# The gain-maximising package: the efficient representative heat pump
# (Vaillant aroTHERM plus 5 kW, ADR-0025) now raises SAP even on this gas
# dwelling, plus the cheap positive-SAP fabric/lighting/secondary measures.
# CAVITY-WALL INSULATION is NOT selected: it earns +2.9 SAP alone, but the
# fabric→ventilation forced dependency (ADR-0016) drags the wall+ventilation
# pair to a NET 1.8 SAP (0.9 on top of the ASHP package), so the Optimiser
# correctly leaves the wall — and therefore its forced ventilation — out.
# (The forced wall→ventilation edge itself is covered by
# test_measure_dependency / test_optimiser; here we prove the end-to-end
# optimise→persist→telescope pipeline on the package the Optimiser keeps.)
# The sample EPC lodges 8 low-energy-unknown bulbs (LED upgrade, ADR-0023)
# and an electric secondary heater (SAP 691, removal offered per ADR-0028).
assert set(by_type) == {
"cavity_wall_insulation",
"suspended_floor_insulation",
"mechanical_ventilation",
# The sample EPC lodges 8 low-energy-unknown bulbs, so the LED upgrade is
# a cheap positive-SAP candidate the Optimiser also keeps (ADR-0023).
"low_energy_lighting",
# The efficient representative heat pump (Vaillant aroTHERM plus 5 kW,
# ADR-0025) now raises SAP even on this gas dwelling, so the Optimiser
# also keeps the ASHP bundle in the least-cost-to-band package (ADR-0024).
"air_source_heat_pump",
# The sample lodges an electric secondary (SAP 691), so removal is offered
# (ADR-0028); the Optimiser keeps it in its all-beneficial-measures package
# — its SAP gain is 0 once the ASHP (category 4) ignores the secondary, but
# the heater is still physically removed at its own cost.
"secondary_heating_removal",
}
# Each persisted measure carries the catalogue id of the Product it installs
# (the MaterialRow ids seeded above), replacing the retired
# recommendation_materials BOM with a single material_id on the row.
assert by_type["cavity_wall_insulation"].material_id == 1
assert by_type["air_source_heat_pump"].material_id == 5
assert by_type["suspended_floor_insulation"].material_id == 2
assert by_type["mechanical_ventilation"].material_id == 3
assert by_type["low_energy_lighting"].material_id == 4
assert by_type["secondary_heating_removal"].material_id == 9
for rec in rec_rows:
@ -414,27 +414,12 @@ def test_modelling_optimises_and_persists_a_multi_measure_plan(
assert rec.already_installed is False
assert rec.sap_points is not None
assert rec.estimated_cost is not None
# The forced ventilation costs two £450 units and is priced even though it
# was never a free choice in the pool.
vent_cost: float | None = by_type["mechanical_ventilation"].estimated_cost
assert vent_cost is not None
assert abs(vent_cost - 900.0) <= 1e-6
# The insulation measures earn positive SAP; ventilation's contribution is
# not positive (it only ever costs SAP — ADR-0016).
wall_sap: float | None = by_type["cavity_wall_insulation"].sap_points
vent_sap: float | None = by_type["mechanical_ventilation"].sap_points
assert wall_sap is not None and vent_sap is not None
assert wall_sap > 0.0
assert vent_sap <= 0.0
# Per-measure bill savings (telescoping cascade, ADR-0014 amendment): each
# measure carries its delivered-kWh and £ saving, and they telescope exactly
# to the Plan's headline savings. Ventilation increases energy, so its
# savings are negative — and the telescoping still holds.
# to the Plan's headline savings.
for rec in rec_rows:
assert rec.kwh_savings is not None
assert rec.energy_cost_savings is not None
vent_kwh: float | None = by_type["mechanical_ventilation"].kwh_savings
assert vent_kwh is not None and vent_kwh < 0.0
kwh_total: float = sum(rec.kwh_savings or 0.0 for rec in rec_rows)
cost_total: float = sum(rec.energy_cost_savings or 0.0 for rec in rec_rows)
assert plan.energy_consumption_savings is not None