feat(modelling): ASHP decommission fallbacks for off-sheet systems

Slice 4 of ADR-0025 costing. ASHP is offered to any house regardless of fuel,
so _decommission now prices a fallback instead of raising: no system -> 0,
electric room/panel heaters -> electric-storage line, anything else -> gas
line (representative default). Never blocks ASHP eligibility.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-06-06 20:42:14 +00:00
parent 22612a19eb
commit 9860f06864
2 changed files with 36 additions and 1 deletions

View file

@ -136,7 +136,15 @@ class Products:
return _DECOMMISSION_OIL
if inputs.existing_system is AshpExistingSystem.LPG:
return _DECOMMISSION_LPG
raise ValueError(f"no decommission rate for {inputs.existing_system}")
# Systems off the rate sheet: ASHP is still offered (ADR-0025), so price
# a fallback rather than raise. Nothing to remove for no system; electric
# room/panel heaters are comparable work to storage heaters; anything
# else takes the gas wet-system line as a representative default.
if inputs.existing_system is AshpExistingSystem.NONE:
return 0.0
if inputs.existing_system is AshpExistingSystem.ELECTRIC_OTHER:
return _DECOMMISSION_ELECTRIC_STORAGE_SMALL if inputs.is_small_property else _DECOMMISSION_ELECTRIC_STORAGE_LARGE
return _DECOMMISSION_GAS
def _distribution(self, inputs: AshpCostInputs) -> float:
radiators: int = max(_MIN_RADIATORS, min(_MAX_RADIATORS, inputs.radiator_count))

View file

@ -84,3 +84,30 @@ def test_reusable_wet_system_prices_a_flush_plus_half_the_distribution() -> None
# Assert — decommission 720 + pump 9840 + cylinder 2382.60 + distribution
# (flush 168 + 0.5 x 4152 = 2244) = 15186.60.
assert abs(cost.total - 15186.60) <= 1e-9
def _small_no_reuse(system: AshpExistingSystem) -> AshpCostInputs:
"""A small dwelling, 4 kW band, 7 radiators, no reusable wet system — pump
9720 + cylinder 2382.60 + distribution (7) 3618 = 15720.60 common base."""
return AshpCostInputs(
existing_system=system,
is_small_property=True,
design_heat_loss_kw=4.0,
radiator_count=7,
has_reusable_wet_system=False,
)
def test_decommission_falls_back_for_systems_not_on_the_rate_sheet() -> None:
# Arrange — the rate sheet covers gas/oil/LPG/electric-storage, but ASHP is
# offered to any house regardless of fuel (ADR-0025): no system costs nothing
# to remove; electric room/panel heaters use the electric-storage line; any
# other system defaults to the gas line — never a raise (that would wrongly
# block ASHP eligibility).
products = Products()
base = 15720.60
# Act / Assert
assert abs(products.ashp_bundle_cost(_small_no_reuse(AshpExistingSystem.NONE)).total - (base + 0.0)) <= 1e-9
assert abs(products.ashp_bundle_cost(_small_no_reuse(AshpExistingSystem.ELECTRIC_OTHER)).total - (base + 570.0)) <= 1e-9
assert abs(products.ashp_bundle_cost(_small_no_reuse(AshpExistingSystem.OTHER)).total - (base + 720.0)) <= 1e-9