mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
The measures a run considers should come from the Scenario, not a CLI flag.
The live scenario table persists exclusions only (no inclusions column), as a
Postgres text-array of exact MeasureType values.
- Scenario gains `exclusions: frozenset[MeasureType]` + `considered_measures()`
(all measures minus the excluded ones, or None when none are excluded).
- ScenarioModel.to_domain parses the `{a,b,c}` exclusions array into
MeasureTypes, raising on a token that is not an exact MeasureType value
(no high-level category expansion), per the strict-enum convention.
- ModellingOrchestrator._plan_for derives the allowlist from the Scenario's
exclusions, combined (intersection) with any explicit considered_measures
override via the new `combine_considered_measures`.
- run_modelling_e2e sources the allowlist from the Scenario; --measures /
--exclude-measures become optional overlays (e.g. the technical
secondary_heating_removal exclusion the catalogue cannot yet stock).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
43 lines
1.3 KiB
Python
43 lines
1.3 KiB
Python
"""The Scenario's measure scoping: its exclusions imply the allowlist the run
|
|
considers (the live `scenario` table persists exclusions only — no inclusions)."""
|
|
|
|
from domain.modelling.measure_type import MeasureType
|
|
from domain.modelling.scenario import Scenario
|
|
|
|
|
|
def _scenario(exclusions: frozenset[MeasureType]) -> Scenario:
|
|
return Scenario(
|
|
id=1,
|
|
goal="Increasing EPC",
|
|
goal_value="C",
|
|
budget=None,
|
|
is_default=True,
|
|
exclusions=exclusions,
|
|
)
|
|
|
|
|
|
def test_no_exclusions_considers_every_measure() -> None:
|
|
# Arrange
|
|
scenario = _scenario(frozenset())
|
|
|
|
# Act
|
|
considered = scenario.considered_measures()
|
|
|
|
# Assert — None means "consider all" (the unrestricted default).
|
|
assert considered is None
|
|
|
|
|
|
def test_exclusions_imply_the_complement_allowlist() -> None:
|
|
# Arrange — exclude solar PV and ASHP.
|
|
scenario = _scenario(
|
|
frozenset({MeasureType.SOLAR_PV, MeasureType.AIR_SOURCE_HEAT_PUMP})
|
|
)
|
|
|
|
# Act
|
|
considered = scenario.considered_measures()
|
|
|
|
# Assert — every modelled measure survives except the two excluded ones.
|
|
assert considered is not None
|
|
assert MeasureType.SOLAR_PV not in considered
|
|
assert MeasureType.AIR_SOURCE_HEAT_PUMP not in considered
|
|
assert considered == frozenset(MeasureType) - scenario.exclusions
|