Fabric short of the target is topped up with non-fabric measures 🟥

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-09 11:36:43 +00:00
parent 9ad2c2edfd
commit e880ae868c

View file

@ -117,3 +117,30 @@ def test_fabric_reaching_the_target_excludes_non_fabric_measures() -> None:
assert abs(package.score.sap_continuous - 70.0) <= 1e-9
def test_fabric_short_of_target_is_topped_up_with_non_fabric_measures() -> None:
# Arrange — all the fabric there is (the wall, +5) cannot reach the target;
# phase 2 must add the heat pump on top of the retained fabric.
groups: list[list[ScoredOption]] = [
[_scored("cavity_wall_insulation", gain=5.0, cost=1000.0, overlay=_WALL_OVERLAY)],
[_scored("air_source_heat_pump", gain=20.0, cost=8000.0, overlay=_HEATING_OVERLAY)],
]
scorer = _StubScorer(base=60.0, wall=5.0, roof=0.0, heating=20.0)
# Act — target 75 (gain 15); fabric alone tops out at 65.
package: OptimisedPackage = optimise_package_fabric_first(
groups=groups,
scorer=scorer,
baseline_epc=build_epc(),
budget=20000.0,
target_sap=75.0,
)
# Assert — the fabric is kept and the heat pump lands on top of it; the
# score is the truthful whole-package figure (60 + 5 + 20).
assert _selected_types(package) == {
"cavity_wall_insulation",
"air_source_heat_pump",
}
assert abs(package.score.sap_continuous - 85.0) <= 1e-9