mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs(modelling): handover — per-measure bill savings landed (telescoping cascade)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b976c3abd2
commit
ae5bbd0646
1 changed files with 12 additions and 5 deletions
|
|
@ -1,6 +1,6 @@
|
|||
# HANDOVER — Modelling stage rebuild
|
||||
|
||||
**Branch:** `feature/bill-derivation` (worktree `/workspaces/home/hestia-worktrees/model-assemble-new-backend`). **HEAD:** `198122d1`.
|
||||
**Branch:** `feature/bill-derivation` (worktree `/workspaces/home/hestia-worktrees/model-assemble-new-backend`). **HEAD:** `b976c3ab`.
|
||||
**PRD:** GitHub `Hestia-Homes/Model#1152`, sliced into #1153–#1161. **All slices #1153–#1161 closed.**
|
||||
|
||||
## Issue status
|
||||
|
|
@ -101,12 +101,19 @@ A `/grill-with-docs` pass designed the Modelling Bill-Derivation slice (ADR-0014
|
|||
|
||||
Key properties: **fuel-switch is handled for free** — we bill the fully-overlaid post-package `SapResult`, so a future oil→ASHP measure prices at the new fuel via `sap_code_to_fuel` (no per-measure fuel bookkeeping). Baseline and post are priced at one `FuelRates` snapshot, so the delta is rate-consistent. Carries ADR-0014's **appliances+cooking-stubbed-at-0** limitation (shared with Baseline, so savings stay consistent).
|
||||
|
||||
## Bill-Derivation: per-measure bill savings (`e79ffabf`→`b976c3ab`) — DONE
|
||||
|
||||
Filled `recommendation.kwh_savings` + `energy_cost_savings` via the **telescoping bill cascade** over the role-3 best-practice order. 3 slices, all green + pyright-strict-clean:
|
||||
|
||||
- **`e79ffabf`** — enabling refactor: pulled the cumulative-prefix scoring out of `marginal_impacts` into a reusable `scoring.cascade_scores(scorer, baseline, overlays) -> list[Score]` (index 0 = baseline, one `calculate` per prefix) + a pure `marginals_from_scores`. Each Score carries its `SapResult`, so the bill cascade re-bills the same prefixes the role-3 attribution scores — **no extra `calculate`**. `marginal_impacts` now delegates (behaviour unchanged).
|
||||
- **`7e79c30a`** — `PlanMeasure` grows optional `kwh_savings` (delivered energy) + `energy_cost_savings` (£), signed so positive = saving, `None` until billed. `RecommendationRow` declares the live `recommendation.kwh_savings`/`energy_cost_savings` columns + maps them (None→NULL). Vestigial `recommendation.energy_savings` stays **undeclared** (legacy = 0). No FE migration (columns already live).
|
||||
- **`b976c3ab`** — `_plan_for` scores baseline + every prefix once via `cascade_scores`, bills each at one Fuel Rates snapshot, and takes **consecutive Bill deltas** as each measure's marginal delivered-kWh + £ saving. The Plan's `baseline_bill`/`post_bill` are now the **same cascade endpoints** (`bills[0]`/`bills[-1]`), so per-measure savings telescope **exactly** to the headline savings — pinned on the real calculator (Σ per-measure == plan totals, abs ≤ 1e-6). Ventilation's saving is **negative** and still telescopes. Added `Bill.total_consumption_kwh` (shared by Plan + orchestrator); dropped the redundant standalone baseline `calculate`.
|
||||
|
||||
Key property: `MeasureImpact.energy_savings_kwh_per_yr` is *primary* energy and does **not** feed `kwh_savings` — `kwh_savings` is **delivered** energy from the Bill section kWh. Carries ADR-0014's appliances+cooking-stubbed-at-0 limitation.
|
||||
|
||||
## What's left
|
||||
|
||||
**Per-measure bill savings (next slice — designed, not built):** fill `recommendation.kwh_savings` + `energy_cost_savings` via a **telescoping bill cascade** over the role-3 best-practice order (fabric → heating → renewables): re-bill each cumulative prefix (reusing the per-prefix `sap_result`s from the role-3 cascade — no extra calls) and diff, telescoping exactly to the plan totals. Per-measure savings can be **negative** (ventilation increases energy) and still telescope. `recommendation.energy_savings` is **vestigial** (legacy = 0) — leave NULL. Note: `MeasureImpact.energy_savings_kwh_per_yr` is *primary* energy, not delivered — it does **not** feed `kwh_savings`.
|
||||
|
||||
|
||||
**Deferred fronts** (open, post-#1161): exclusion-filtering of the candidate pool (deferred from #1160); a **Bill-Derivation slice** that re-runs bills on the post-package EPC to fill the deferred energy/bill columns (`plan.post_energy_consumption`/`post_energy_bill`, `recommendation.kwh_savings`/`energy_cost_savings`); persist **unselected alternatives** (`default=False` rows linked via `plan_id`) for the swap-in UX — open ADR-0016 question: what impact figure they carry; promote `ProductRepository` to the DB+file composite; non-EPC goal objectives (Energy Savings, Reducing CO2) in the optimiser. Possible extension of the ventilation trigger set to roof insulation (now a one-line data edit in `MEASURES_NEEDING_VENTILATION`); and making the dependency builder lazy (thunk) so the Product is only fetched when a trigger is actually selected.
|
||||
**Deferred fronts** (open, post-#1161): exclusion-filtering of the candidate pool (deferred from #1160); persist **unselected alternatives** (`default=False` rows linked via `plan_id`) for the swap-in UX — open ADR-0016 question: what impact figure they carry; promote `ProductRepository` to the DB+file composite; non-EPC goal objectives (Energy Savings, Reducing CO2) in the optimiser. Possible extension of the ventilation trigger set to roof insulation (now a one-line data edit in `MEASURES_NEEDING_VENTILATION`); and making the dependency builder lazy (thunk) so the Product is only fetched when a trigger is actually selected.
|
||||
|
||||
## Key references
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue