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>
3.7 KiB
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
plancolumns). There is noplan_phasetable and nophasecolumn. - 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 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:
- Add a
plan_phasetable; give each existing live Plan exactly one Plan Phase and back-fill its current Optimised Package + post-retrofit figures into that single phase. - Add ordered phases to the Scenario aggregate (allowlist / budget / target per phase).
- 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.