Model/repositories/product
Khalim Conn-Kowlessar 4ce2a71871 feat(scripts): one-pass e2e run — baseline + plans + prediction + recovery
Make run_modelling_e2e the single script that does everything for a portfolio,
so the 291-property run needs one invocation with per-property recovery (no
all-or-nothing chunking):

- On --persist, a lodged-EPC Property now also gets its Baseline Performance
  row written via PropertyBaselineOrchestrator (per Property, so one bad cert
  does not abort the batch). Predicted (EPC-less) Properties have no lodged
  figures, so they get a Plan but no baseline row.
- The run CSV gains api_sap (register) vs baseline_sap (calculator) + sap_delta,
  so calculator-vs-API divergence is reviewable per property.

Fill the off-catalogue overlay for the measures the live material catalogue
cannot price, so they stop crashing the run:

- double_glazing (£550/window) and secondary_glazing (£400/window): priced
  per window (the generator multiplies by single-glazed window count, matching
  the legacy window_glazing). Grounded in 2025/26 UK installed costs; per-window
  is the right unit for windows (fixed per-unit install dominates) — per-m2 fits
  walls/floors, not glazing.
- gas_boiler_upgrade / system_tune_up / system_tune_up_zoned: these are priced
  off the heating rate sheet (Products()), with get() reading the catalogue only
  for an id — so the overlay entry exists to satisfy that lookup (material_id
  stays None, as with ASHP); the rate sheet remains authoritative.

Validated on a 12-property sample (incl. a secondary-glazing case and a
SAP-Schema-16.2 cert): 12/12 baseline rows + plans, 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 08:24:03 +00:00
..
__init__.py feat(modelling): ProductRepository + Postgres materials-table source 2026-06-03 08:32:38 +00:00
composite_product_repository.py feat(modelling): price secondary-heating-removal from an off-catalogue overlay 2026-06-19 14:49:51 +00:00
off_catalogue_costs.json feat(scripts): one-pass e2e run — baseline + plans + prediction + recovery 2026-06-23 08:24:03 +00:00
product_json_repository.py fix(modelling): offer ASHP when the catalogue has no ASHP row 2026-06-16 14:55:41 +00:00
product_postgres_repository.py fix(modelling): offer ASHP when the catalogue has no ASHP row 2026-06-16 14:55:41 +00:00
product_repository.py fix(modelling): offer ASHP when the catalogue has no ASHP row 2026-06-16 14:55:41 +00:00