diff --git a/repositories/property/landlord_override_overlays.py b/repositories/property/landlord_override_overlays.py index b65cf5d29..7477cc785 100644 --- a/repositories/property/landlord_override_overlays.py +++ b/repositories/property/landlord_override_overlays.py @@ -67,9 +67,22 @@ _COMPONENT_OVERLAYS: dict[str, Callable[[str, int], Optional[EpcSimulation]]] = } +# Components whose overlay must be applied LAST so an explicit value wins a +# default another overlay dragged. `apply_simulations` is last-wins and override +# rows arrive in arbitrary order, so a `main_fuel` override must be applied after +# the `main_heating_system` archetype, whose natural-fuel default it overrides +# (ADR-0041) — e.g. "smokeless coal" must beat a solid-fuel room heater's coal +# default. +_APPLY_LAST: frozenset[str] = frozenset({"main_fuel"}) + + def overlays_from(overrides: ResolvedPropertyOverrides) -> list[EpcSimulation]: overlays: list[EpcSimulation] = [] - for row in overrides.rows: + # Stable sort: non-`_APPLY_LAST` rows keep their order, `main_fuel` goes last. + ordered_rows = sorted( + overrides.rows, key=lambda row: row.override_component in _APPLY_LAST + ) + for row in ordered_rows: mapper = _COMPONENT_OVERLAYS.get(row.override_component) if mapper is None: continue