mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs(modelling): ADR-0014 amendment — cross-stage billing + Modelling post-package bills
Records the /grill-with-docs design for the Modelling Bill-Derivation slice: Bill Derivation is cross-stage (relocate Bill/EnergyBreakdown/BillDerivation/ sap_fuel to a neutral domain/billing/); Modelling bills the fully-overlaid post-package SapResult (so fuel-switch measures price at the new fuel for free), diffing against the baseline at the same FuelRates snapshot; the post-package and baseline SapResults are captured from scores the optimiser/orchestrator already compute (Score.sap_result), so no second calculate; FuelRatesRepository is constructor-injected into ModellingOrchestrator mirroring Baseline; plan-level columns this slice, per-measure telescoping bill cascade next (energy_savings is vestigial, left NULL). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
660dc54246
commit
75ba5dd744
1 changed files with 16 additions and 0 deletions
|
|
@ -136,3 +136,19 @@ the fuel each end use burns come from?* Resolved in a `/grill-with-docs` session
|
|||
`BillSection` gains `COOLING` (kWh from `SapResult.space_cooling_fuel_kwh_per_yr`, electricity by
|
||||
construction), so §6's layout gains a `cooling_kwh` + `cooling_cost_gbp` column pair (FE-owned
|
||||
Drizzle migration).
|
||||
|
||||
## Amendment (2026-06-03): Bill Derivation is cross-stage; the Modelling stage prices the post-package end-state
|
||||
|
||||
Bill Derivation is no longer Baseline-only — the **Modelling** stage now re-runs it on the **Optimised Package** to produce post-retrofit bills and savings. Decided in a `/grill-with-docs` session.
|
||||
|
||||
- **Bill Derivation is a cross-stage domain concern → relocate to `domain/billing/`.** `Bill` / `EnergyBreakdown` / `BillDerivation` / `sap_fuel` were under `domain/property_baseline/` only because Baseline was built first. Two stages now consume them, and a `modelling → property_baseline` import would couple two stages ADR-0011 keeps independent under a name that wrongly implies ownership. They move to a neutral `domain/billing/` (`Fuel`/`FuelRates` already live in the shared `domain/fuel_rates/`). Mechanical move + import rewrite; covered by the existing Baseline tests.
|
||||
|
||||
- **Modelling bills the simulated *end-state*, never adjusts the baseline bill.** The post-retrofit bill is `BillDerivation.derive(EnergyBreakdown.from_sap_result(post_package_sap_result))`, where the `SapResult` comes from scoring the fully-overlaid `EpcPropertyData` (all selected Simulation Overlays + injected dependencies). **This is what makes fuel-switch measures correct for free:** a measure that switches heating fuel (e.g. oil → electric ASHP) changes the heating fuel *code* on that `SapResult`, so `sap_code_to_fuel` prices it at the *new* fuel automatically — no per-measure fuel bookkeeping. Savings are `baseline − post`, both priced at the **same** `FuelRates` snapshot (read once per run), so the delta is never polluted by a rate change.
|
||||
|
||||
- **No second calculator pass.** The post-package `SapResult` is the one the optimiser's whole-package re-score (role 2) already computed; it rides on the `Score` (`Score.sap_result`, populated by `PackageScorer`, ignored by the optimiser — so the optimiser stays `Score`-only and its stub-scorer tests are unaffected). Likewise the baseline `SapResult` is the one the orchestrator already scores for the role-3 cascade and the target gain. Billing reuses both — zero extra `calculate`.
|
||||
|
||||
- **`FuelRatesRepository` is constructor-injected into `ModellingOrchestrator`**, mirroring the Baseline orchestrator — `get_current()` once per `run()`, one `BillDerivation` reused across the batch. Not on the `UnitOfWork` (read-once reference data, ADR-0011). The extra per-pipeline read (Baseline + Modelling each resolve rates) is accepted; a shared/injected snapshot is a future optimisation.
|
||||
|
||||
- **Plan-level first, per-measure savings next (telescoping cascade).** This slice fills the plan columns (`post_energy_bill`, `post_energy_consumption`, `energy_bill_savings`, `energy_consumption_savings`). Per-measure `recommendation.kwh_savings` / `energy_cost_savings` come from a **bill cascade over the role-3 best-practice order** (fabric → heating → renewables) — re-bill each cumulative prefix and diff, telescoping exactly to the plan totals (mirroring the SAP role-3 attribution; reuses the per-prefix `sap_result`s, no extra calls). Per-measure savings can be **negative** (ventilation increases energy) and still telescope. The legacy `recommendation.energy_savings` column is **vestigial** (legacy set it to `0`; the canonical delivered-energy field is `kwh_savings`) — left NULL.
|
||||
|
||||
- **Limitation carried over.** The "Appliances + cooking kWh stubbed at 0" deferral above still applies — Modelling's post-package bill understates by the same unregulated-electricity load until those fields land on `SapResult`. Baseline and Modelling share the gap, so baseline-vs-post savings remain consistent.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue