Remove the superseded role-1 impacts scorer; signals carry the objective currency 🟪

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-09 13:19:22 +00:00
parent e329c50fa3
commit c70f6730a3
3 changed files with 9 additions and 40 deletions

View file

@ -33,8 +33,9 @@ from domain.modelling.simulation import EpcSimulation
@dataclass(frozen=True)
class ScoredOption:
"""A candidate Measure Option paired with its role-1 (independent-vs-
baseline) SAP gain the optimiser's input signal. Cost is read from the
Option; the gain is supplied by scoring."""
baseline) gain in the goal objective's currency — SAP points by default,
kg CO2 / £ saved for the goal-aligned Scenarios (ADR-0062). Cost is read
from the Option; the gain is supplied by scoring."""
option: MeasureOption
sap_gain: float

View file

@ -83,38 +83,6 @@ def marginal_impacts(
return marginals_from_scores(cascade_scores(scorer, baseline, overlays))
def independent_option_impacts(
scorer: PackageScorer,
baseline: EpcPropertyData,
options: Sequence[MeasureOption],
) -> list[MeasureImpact]:
"""Score each Option's overlay independently against the baseline (role 1 —
the optimiser's approximate input signal). Each *distinct* Simulation Overlay
is scored once (Options sharing an overlay reuse the result), so the baseline
is scored once plus one score per distinct overlay. Results follow the input
order. These figures are an approximate signal never surface them as a
measure's true impact."""
base: Score = scorer.score(baseline, [])
scored: list[tuple[EpcSimulation, MeasureImpact]] = []
impacts: list[MeasureImpact] = []
for option in options:
cached = next(
(impact for overlay, impact in scored if overlay == option.overlay), None
)
if cached is None:
current: Score = scorer.score(baseline, [option.overlay])
cached = MeasureImpact(
sap_points=current.sap_continuous - base.sap_continuous,
co2_savings_kg_per_yr=base.co2_kg_per_yr - current.co2_kg_per_yr,
energy_savings_kwh_per_yr=(
base.primary_energy_kwh_per_yr - current.primary_energy_kwh_per_yr
),
)
scored.append((option.overlay, cached))
impacts.append(cached)
return impacts
def independent_option_signals(
scorer: PackageScorer,
baseline: EpcPropertyData,

View file

@ -16,7 +16,7 @@ from domain.modelling.recommendation import MeasureOption
from domain.modelling.scoring.scoring import (
MeasureImpact,
cascade_scores,
independent_option_impacts,
independent_option_signals,
marginal_impacts,
marginals_from_scores,
)
@ -64,7 +64,7 @@ def _option(overlay: EpcSimulation) -> MeasureOption:
)
def test_independent_option_impacts_score_each_distinct_overlay_once() -> None:
def test_independent_option_signals_score_each_distinct_overlay_once() -> None:
# Arrange
baseline: EpcPropertyData = build_epc()
scorer = _CountingScorer()
@ -86,15 +86,15 @@ def test_independent_option_impacts_score_each_distinct_overlay_once() -> None:
options = [_option(overlay_a), _option(overlay_a_dup), _option(overlay_b)]
# Act
impacts: list[MeasureImpact] = independent_option_impacts(
scorer, baseline, options
signals: list[float] = independent_option_signals(
scorer, baseline, options, lambda score: score.sap_continuous
)
# Assert
# baseline scored once + one score per DISTINCT overlay (a, b) = 3, not 4
assert scorer.calls == 3
assert impacts[0].sap_points == impacts[1].sap_points == 2.0
assert impacts[2].sap_points == 3.0
assert signals[0] == signals[1] == 2.0
assert signals[2] == 3.0
def test_single_overlay_marginal_is_its_improvement_over_baseline() -> None: