From 3ef432c8b2ef4622601c6c974e2a78c571116560 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 7 Jul 2026 21:57:53 +0000 Subject: [PATCH] =?UTF-8?q?ADR-0058:=20Sub-Ladder=20PV=20Configurations=20?= =?UTF-8?q?give=20small=20roofs=20the=20array=20their=20caps=20allow=20?= =?UTF-8?q?=F0=9F=9F=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Grilled decisions (issue #1496): 2-panel floor, every rung 2..floor(cap), pro-rata per-segment yield (conservative), fill-by-generation, same cap regime as today (no new roof gate), symmetric battery pairing. Glossary gains "Sub-Ladder Configuration" ("trimmed"/"synthesized" deliberately avoided — both collide with existing vocabulary). Co-Authored-By: Claude Fable 5 --- CONTEXT.md | 6 +- ...adder-pv-configurations-for-small-roofs.md | 90 +++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 docs/adr/0058-sub-ladder-pv-configurations-for-small-roofs.md diff --git a/CONTEXT.md b/CONTEXT.md index caaf3029e..d24ce42fd 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -317,9 +317,13 @@ The bound that limits a **Solar PV Recommendation**'s array to the dwelling's *o _Avoid_: roof-area haircut (overloads the MCS coverage haircut), double-property halving (the legacy semi-detached-only mechanism this replaces) **Solar PV Recommendation**: -The single "Solar PV" **Recommendation** for a Property, carrying competing whole-array **Measure Options** built from the **Solar Potential** (ADR-0026). Up to **five conservatively-sized array configs** (capped, ranked by energy generation as the size-suitability proxy; deliberately *not* full-roof — imagery can miss obstructions, so a coverage/edge-setback haircut applies per MCS, and the **Dwelling-Roof Cap** bounds the array to the dwelling's own roof under **Footprint Conflation**), each offered **with and without a battery** (≤ 10 Options). Each Option is priced at a **single price point** from the rate sheet (kWp band + scaffolding-by-elevation + optional battery/diverter) — no multi-product price variants. The PV Overlay sets `photovoltaic_arrays` (one per segment: peak_power, orientation, pitch, overshading) plus `pv_diverter_present`, `pv_connection`, and **`is_dwelling_export_capable=True`** (an export meter is ensured post-install); the battery variant adds `pv_batteries`. +The single "Solar PV" **Recommendation** for a Property, carrying competing whole-array **Measure Options** built from the **Solar Potential** (ADR-0026). Up to **five conservatively-sized array configs** (capped, ranked by energy generation as the size-suitability proxy; deliberately *not* full-roof — imagery can miss obstructions, so a coverage/edge-setback haircut applies per MCS, and the **Dwelling-Roof Cap** bounds the array to the dwelling's own roof under **Footprint Conflation**), each offered **with and without a battery** (≤ 10 Options). Each Option is priced at a **single price point** from the rate sheet (kWp band + scaffolding-by-elevation + optional battery/diverter) — no multi-product price variants. The PV Overlay sets `photovoltaic_arrays` (one per segment: peak_power, orientation, pitch, overshading) plus `pv_diverter_present`, `pv_connection`, and **`is_dwelling_export_capable=True`** (an export meter is ensured post-install); the battery variant adds `pv_batteries`. When no Google rung fits under the caps, **Sub-Ladder Configurations** (ADR-0058) supply the small rungs instead of dropping PV entirely. _Avoid_: solar bundle (PV is competing sized Options, not one fixed bundle like ASHP) +**Sub-Ladder Configuration**: +A PV array configuration Modelling derives **below Google's smallest offered rung**, so a small roof gets the array its caps allow instead of no PV at all (ADR-0058). Derived only when no `solarPanelConfigs` rung fits under the caps and at least 2 panels do: north planes dropped first, the rung's panels filled from segments ranked by per-panel yield (the **Dwelling-Roof Cap**'s fill-by-generation precedent), each kept segment's yearly energy scaled **pro-rata** (conservative — Google places panels best-first). One rung per whole panel count from **2** (the install floor) up to the cap; both caps (0.70 × max, **Dwelling-Roof Cap**) unchanged. Flows through the standard Option construction (battery pairing, pricing, PV Overlay) with no special cases. +_Avoid_: trimmed configuration ("trimmed" already means the north-segment drop), synthesized configuration ("synthesis" belongs to Reduced-Field Synthesis / EPC Prediction), minimum array (names the 2-panel floor, not the derived-rung concept) + **Solar PV Eligibility**: The rule fixing whether the **Solar PV Recommendation** is offered (ADR-0026): a **house or bungalow**, **not listed and not heritage**, with **no existing PV**, and a **feasible Solar Potential** (the Google Solar API returned usable, non-north roof segments). Crucially a **conservation area does NOT block PV** — panels are offered (installed sympathetically), so the planning gate is `not blocks_internal` (listed/heritage only), **not** `blocks_external`; this is the opposite of an external fabric measure like EWI, and is deliberate (legacy + planning practice allow conservation-area PV on non-prominent roofs). Flats/maisonettes (building-level shared roof) are deferred. _Avoid_: blocking conservation-area PV (only listed/heritage block), roof-area-from-floor-area estimate (eligibility uses the real Solar Potential) diff --git a/docs/adr/0058-sub-ladder-pv-configurations-for-small-roofs.md b/docs/adr/0058-sub-ladder-pv-configurations-for-small-roofs.md new file mode 100644 index 000000000..7c6e936bf --- /dev/null +++ b/docs/adr/0058-sub-ladder-pv-configurations-for-small-roofs.md @@ -0,0 +1,90 @@ +--- +status: accepted (extends ADR-0026 and ADR-0038) +--- + +# Sub-Ladder PV Configurations give small roofs the array their caps allow + +ADR-0026 sizes a PV array by picking from Google's `solarPanelConfigs` ladder +under a conservative cap (0.70 × `maxArrayPanelsCount`, min'd with the +ADR-0038 Dwelling-Roof Cap when it resolves). Google's ladder typically starts +at **4 panels**, so on a small roof the cap falls below the smallest rung and +the feasible set is **empty** — the dwelling silently gets **no Solar PV +Measure Option at all** rather than a small array. ADR-0038 already states the +intent "never emit a zero-panel or unbounded array", but that governs the cap +fallback, not the ladder; the ladder cliff violated its spirit. + +Motivation: portfolio 824 / scenario 1278 audit (2026-07-07). Property 750701 +(UPRN 100010328594) — an unrestricted house short of goal C at D/67 on an +unlimited budget — has `maxArrayPanelsCount = 5` with rungs at 4 and 5 panels; +cap 0.70 × 5 = 3.5 < 4 → no PV offered, while ~2 SAP of feasible PV would +plausibly reach C. The cliff affects every small-roofed house in every +portfolio, silently. + +## Decision + +**When no Google rung fits under the caps, derive Sub-Ladder Configurations — +array rungs below Google's smallest offered configuration — instead of +dropping PV entirely.** + +- **Trigger**: the feasible set (north-dropped Google configs with + `panels_count <= panel_cap`) is empty AND `floor(panel_cap) >= 2`. When + `floor(panel_cap) < 2`, or nothing survives the north-segment drop, the + outcome stays no-PV — a roof that cannot take 2 panels is never offered + them. +- **Floor = 2 panels** — the practical install floor. Economics stay the + Optimiser's job (ADR-0024/0026 doctrine: eligibility and sizing encode + physical installability only); on least-cost-to-target a poor-£/kWh small + array is bought exactly when it is the only route to the goal band, which + is when the landlord wants it offered. +- **Every rung, not one**: emit a Sub-Ladder Configuration at every whole + panel count from 2 to `floor(panel_cap)` (in practice at most rungs 2 and + 3 — the trigger implies `floor(panel_cap) <= 3`). Preserves ADR-0026's + genuine size/cost choice; the Optimiser stops at the cheapest array that + reaches goal. +- **Derivation**: start from Google's smallest rung, drop north planes first + (as for every config), then fill the rung's panel count from the remaining + segments **ranked by per-panel yield** — the ADR-0038 "fill by generation" + precedent. +- **Yield accounting is pro-rata per segment**: a kept segment contributes + `yearly_energy × kept_panels / segment_panels`. Provably conservative — + Google places panels best-first within a segment, so the kept panels' true + yield ≥ the pro-rata figure. Needs no new `SolarPotential` projection + fields. +- **Cap regime unchanged, no new gate**: the same `min(0.70 × max, + dwelling-roof budget)` applies; when the Dwelling-Roof Cap cannot resolve, + the 0.70-Google cap alone governs — exactly as it already does for full + configs, and a smaller array is strictly more conservative than what those + dwellings are offered today. +- **Downstream unchanged**: Sub-Ladder Configurations flow through the + existing option construction — with-and-without battery pairing, single + price point, PV Overlay — with no special cases. + +## Considered options + +- **Floor the cap at Google's smallest rung** (offer the 4-panel config when + the dwelling roof confirms it fits). Rejected: breaches the 70% + conservatism the cap encodes — the cap exists precisely to not trust + Google's maximum placement wholesale. +- **Exact per-panel yields** (extend the projection to carry Google's + `solarPanels` list and sum true kept-panel energies). Rejected for now: + new plumbing for precision that cannot change an Optimiser decision at 2–3 + panels; pro-rata errs conservative. Revisit if sub-ladder sizing ever + extends beyond the small-roof trigger. +- **3-panel floor**. Rejected: gives up the smallest roofs (Google max 3–4 + panels), where 2 panels is all the cap allows and may still clear a + near-boundary goal. +- **Require the Dwelling-Roof Cap to resolve before deriving**. Rejected: + stricter than today's treatment of full configs on unresolved roofs — + an inconsistent trust model. + +## Consequences + +- Small-roofed houses gain a PV path toward goal; on the motivating property + the expected offer is a 3-panel rung (~950 kWh/yr pro-rata from the + 4-panel rung's 1,278). Follow-up: re-model 750701 after implementation to + confirm the +2 SAP to band C. +- A no-PV outcome on a small roof now always means `floor(panel_cap) < 2`, + no usable non-north segment, or ineligibility — never the ladder cliff. +- The audit skill's small-roof expectation (a `solar` row with no `solar_pv` + candidate is not automatically the solar-blind batch bug) shrinks to the + sub-2-panel residue once portfolios are re-modelled.