Replaces sfr/principal_pitch/2_export_data.py, which read the retired
plan_recommendations m2m and recommendation_materials table. The new model
links a recommendation to its plan directly (recommendation.plan_id), keeps
materials inline on the recommendation (material_id), marks the chosen plan
per (scenario, property) with is_default, and stores post-works SAP/EPC and
savings on the plan row (the new SAP calculator's output).
Takes a portfolio id, resolves every modelled scenario (those with plans),
and writes one workbook with a properties sheet per scenario. EPC descriptive
fields are sourced live from the EPC service (property_details_epc is dead);
property_type falls back override -> cert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Heat pump drags category 4 + electricity (29). Meter stays single-rate: a heat
pump does not imply an off-peak tariff the way storage/CPSU do (SAP §12 Rule 3
is conditional), so forcing Dual would mis-bill it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire flag_fuel_mismatch into the two override-resolution paths (the property
repository and the modelling-e2e handler), keeping overlays_from a pure mapping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Compare fuel families (not exact codes), so a solid-fuel room heater refined to
smokeless/dual/biomass is consistent; only a different family (gas/electric on a
solid heater) is logged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
overlays_from now applies main_fuel after main_heating_system (stable sort), so
an explicit landlord fuel wins the natural-fuel default the heating archetype
drags, regardless of override row order. apply_simulations is last-wins.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Solid fuel is ambiguous across coal/wood/smokeless/pellets, so the overlay
defaults to house coal (33, the most common) when no main_fuel override is
given; a specific solid-fuel override still wins by last-wins composition.
Updates the ADR-0041 natural-fuel amendment accordingly (every archetype drags
a natural fuel; solid defaults to coal).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the natural-fuel drag-along rule the overlay now implements: drag a fuel
only where the archetype is unambiguous (electric/gas), leave ambiguous
solid/oil room heaters to the main_fuel override, let a present main_fuel
override win by last-wins composition, and LOG (not raise) a landlord fuel that
contradicts the archetype's natural fuel.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
grill-with-docs output for PRD #1361 Class A. The band-G baselines are not a
fabric/rebaseline bug (walls are correct — landlord asserted as-built); they are
a target-vocabulary gap in the landlord-description heating classifier. The LLM
maps unbounded free-text onto a closed internal taxonomy, but that taxonomy had
9 archetypes vs ~13 RdSAP families, so it overflowed into "Gas CPSU"/storage
(the "convector" collision sent direct-acting room heaters to off-peak storage
403 → SAP ~10).
- ADR-0041: fix the taxonomy not the mapper; unmapped input -> None (keep lodged
EPC, surface to user), never a forced archetype; heat pumps modellable via a
default Table 4a code (no PCDB id); community heating via codes 301/302/304
with a documented DLF-1.50 / boiler-source default.
- CONTEXT.md: sharpen Landlord-Description Classification and the four distinct
vocabularies (landlord / recognised-internal / lodged / SAP code).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `recommendation` table (~26m rows) has no index on `plan_id`, so any query
reaching it via `plan_id` — including the audit's own rollup — seq-scans the
whole table and saturates the shared DB (it blocked the DB during the
portfolio-796 audit). Make the audit safe-by-default:
- statement_timeout (120s) on the audit connection — a hard ceiling so a bad
plan aborts instead of hammering the DB.
- The recommendation rollup (the two solar checks) is now opt-in via
--with-recommendations, and EXPLAIN-gated: it refuses to run (raising
RecommendationScanError) when the plan contains a Seq Scan on recommendation,
which it does on any large portfolio until idx_recommendation_plan_id exists.
- SKILL.md documents the plan_id-no-index trap, the reach-via-property_id /
EXPLAIN-first / confirm-with-user rules, and the index as the real fix.
Verified on 796/1268: default run is bounded and completes (2,952 anomalies over
31,919 properties); --with-recommendations aborts pre-scan portfolio-wide but is
allowed for a single property.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The PV-array (ea7f4f43) and electricity-tariff (6ec09892) mapper fixes shifted
the observed output of five frozen gates that weren't updated alongside:
- has_pv component-accuracy floor 0.9798 -> 0.9697: carrying full-SAP lodged PV
now reads the true has_pv=True for full-SAP PV dwellings, so the leave-one-out
scorer's actual changes (ground-truth-method shift, ADR-0037 pattern).
- uprn_10093116528 80->... pin 82 -> 83: tariff=1 (standard) was wrongly read as
dual/Economy 7; translating to "single" re-prices the gas semi's electricity.
- uprn_10096028301 82 -> 84, uprn_10023444324 80 -> 82 (== lodged 82),
uprn_10023444320 81 -> 83: now credit the lodged sap_energy_source.pv_arrays
the schema previously dropped. Comments document the per-cert PV/Elmhurst
relationship (incl. the mid-floor sibling landing +2 over its lodged integer).
Pre-existing, unrelated failures untouched: the missing
sap_16_0_full_no_floor_dims.json fixture and the RdSAP-21 floor-area test (both
reproduce on origin/main).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>