diff --git a/tests/orchestration/test_ara_first_run_pipeline_integration.py b/tests/orchestration/test_ara_first_run_pipeline_integration.py index 7caffe6f..192f07a5 100644 --- a/tests/orchestration/test_ara_first_run_pipeline_integration.py +++ b/tests/orchestration/test_ara_first_run_pipeline_integration.py @@ -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