Model/domain/billing
Khalim Conn-Kowlessar b976c3abd2 feat(modelling): attribute per-measure bill savings via a telescoping cascade
`_plan_for` now scores the baseline + every cumulative prefix once
(`cascade_scores`, best-practice order) and reuses those Scores for both the
role-3 marginal attribution and a per-measure bill cascade: bill each prefix at
one Fuel Rates snapshot and take consecutive Bill deltas as each measure's
marginal delivered-kWh and £ saving. Saving is signed (ventilation is
negative) and telescopes exactly to the Plan headline savings, because the
Plan's baseline/post Bills are now the same cascade endpoints (`bills[0]` /
`bills[-1]`) — which also drops the redundant standalone baseline `calculate`.

`recommendation.kwh_savings` / `energy_cost_savings` are filled from these.
Adds `Bill.total_consumption_kwh` (shared by Plan + the orchestrator). Pinned
end-to-end on the real calculator: Σ per-measure savings == the Plan totals
(ADR-0014 amendment).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 18:01:11 +00:00
..
__init__.py refactor(billing): relocate Bill Derivation to domain/billing/ (cross-stage) 2026-06-03 17:19:23 +00:00
bill.py feat(modelling): attribute per-measure bill savings via a telescoping cascade 2026-06-03 18:01:11 +00:00
bill_derivation.py refactor(billing): relocate Bill Derivation to domain/billing/ (cross-stage) 2026-06-03 17:19:23 +00:00
sap_fuel.py refactor(billing): relocate Bill Derivation to domain/billing/ (cross-stage) 2026-06-03 17:19:23 +00:00