A goal-aligned scenario without a budget fails loudly 🟩

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Khalim Conn-Kowlessar 2026-07-09 12:59:46 +00:00
parent 102b250e53
commit 6296b2d8fc

View file

@ -182,6 +182,7 @@ class ModellingOrchestrator:
# The Optimiser speaks the goal's currency (ADR-0062): group signals,
# dependency pricing and repair marginals are all measured by this
# objective — SAP by default, carbon reduction for a Reducing-CO2 goal.
_require_budget_for_goal_aligned(scenario)
objective: Callable[[Score], float] = _objective_for(scenario, bill_derivation)
groups: list[list[ScoredOption]] = _scored_candidate_groups(
scorer,
@ -437,6 +438,20 @@ def _scored_candidate_groups(
return groups
def _require_budget_for_goal_aligned(scenario: Scenario) -> None:
"""A goal-aligned Scenario is 'reduce as much as possible within this
budget' — undefined without one (unconstrained, it would recommend every
beneficial measure). Fail the misconfiguration loudly (ADR-0062)."""
if scenario.budget is None and scenario.goal in (
_REDUCING_CO2_GOAL,
_ENERGY_SAVINGS_GOAL,
):
raise ValueError(
f"scenario {scenario.id} has goal {scenario.goal!r} but no budget; "
"goal-aligned scenarios require a budget"
)
def _carbon_reduction(score: Score) -> float:
"""The Reducing-CO2 objective: annual kg CO2 below zero-point, negated so
higher is better (a saved kg scores +1)."""