Model/docs/adr/0005-multi-phase-scenarios-per-phase-recompute.md
Khalim Conn-Kowlessar 772cdd4f5a docs(modelling): #1157 Plan-persistence design review
Outcome of the /grill-with-docs session scoping #1157.

- CONTEXT.md: add **Plan Measure** (the persisted selected Option +
  role-3 attribution + cost); Recommendation stays the candidate.
  Remove Scenario Phase / Plan Phase / Rolled-over Options — multi-phase
  is deferred. Reshape Scenario + Plan to single-phase; fix relationships,
  dialogue, and the "phase" ambiguity note.
- ADR-0005: rewritten to Deferred (multi-phase was speculative
  prospective-client work; single-phase now; future plan_phase back-fill
  path preserved). Stray phase refs cleaned in ADR-0016 / ADR-0009.
- ADR-0017 (new): Plan persistence — reuse the live plan/recommendation
  tables via SQLModel mirrors + a PlanRepository on the UoW; add
  recommendation.plan_id, retire the plan_recommendations m2m; flat
  post-retrofit on plan; idempotent replace; CO2 in tonnes. Unselected
  alternatives + bills noted as deferred directions.
- docs/migrations/recommendation-plan-id.md: the FE-owned Drizzle change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 11:12:54 +00:00

31 lines
3.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Multi-phase scenarios — deferred (speculative)
**Status: Deferred / Out of scope.** Superseded by the single-phase decision taken in a `/grill-with-docs` session (2026-06-03) while scoping the #1157 Plan persistence schema. This ADR previously proposed an *Accepted* multi-phase Scenario aggregate with per-phase recompute against rolling state; that design is **not** being built now. The original proposal is preserved below under "Deferred design" for the day the requirement returns.
## Why deferred
Multi-phase sequencing — letting a user split a Scenario into ordered phases ("fabric this year, heat pump next, solar after"), each with its own measure allowlist / budget / target, and producing Plans shaped to match — came from a **prospective (not current) client**. It is entirely speculative: we may never build it. Baking it into the core domain as an accepted decision made the model "too strong" — it forced a first-class **Scenario Phase** / **Plan Phase** / **Rolled-over Options** vocabulary and a `plan_phase` table into a live product that has no consumer for any of it.
The current goal is to **replicate and improve the existing pipeline**, which is single-phase. So:
- A **Scenario** carries one set of permitted measure types (no ordered phases).
- A **Plan** holds one **Optimised Package** of **Plan Measures** plus the Property's flat post-retrofit figures (the legacy `plan` columns). There is no `plan_phase` table and no `phase` column.
- The terms **Scenario Phase**, **Plan Phase**, and **Rolled-over Options** are removed from `CONTEXT.md`.
This is cheap to reverse: re-introducing phases is additive, and the [ADR-0016](0016-package-rescore-over-warm-start-optimisation.md) scoring split (per-Option signal → whole-package re-score → marginal-cascade attribution) already works against a single package and generalises to per-phase rolling state unchanged.
## Future migration path (when/if the requirement returns)
Scope it properly as a feature in its own right — do **not** retrofit it implicitly. The migration shape we expect:
1. Add a `plan_phase` table; give each existing live **Plan** exactly one Plan Phase and back-fill its current Optimised Package + post-retrofit figures into that single phase.
2. Add ordered phases to the **Scenario** aggregate (allowlist / budget / target per phase).
3. Generalise the Optimiser to run per phase against the **rolling** Effective EPC (phase 1 = baseline; phase 2 = post-phase-1 state; …), so phase ordering becomes load-bearing in the optimisation rather than decorative.
This back-fill keeps every live single-phase Plan valid as a degenerate one-phase case.
## Deferred design (original proposal, for reference)
The Scenario aggregate becomes ordered phases: each phase has a measure-type allowlist, an optional budget, and an optional goal. The pipeline walks the phases in order; for each phase it (1) generates candidate recommendations restricted to the phase's measure types, (2) re-runs scoring against the **rolling** Effective EPC state (baseline for phase 1; post-phase-1 for phase 2; etc.), (3) optimises within the phase's budget/goal, (4) applies the selected package and rolls the state forward.
The rationale was that per-phase recompute makes phase ordering load-bearing in the optimisation, not decorative: installing fabric measures before a heat pump materially changes the heat pump's SAP impact. The cost is ML/calculator calls scaling with `N_phases × N_scenarios × N_candidate_measures` per property. A single-phase Scenario was modelled as `phases: [<one ScenarioPhase>]` with all measure types allowed — i.e. exactly the single-phase product we are now building directly, without the phase machinery.