Commit graph

190 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
927384e5a9 Resolve electric CPSU from the property's fuel, keeping gas CPSU on 120 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:16:10 +00:00
Khalim Conn-Kowlessar
8b0176976d Resolve electric CPSU from the property's fuel, keeping gas CPSU on 120 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 16:12:00 +00:00
Khalim Conn-Kowlessar
de7bfc5dfe Reclassify Gas CPSU dumping-ground overrides via the generalized main-heating reclassify 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 15:58:29 +00:00
Jun-te Kim
10e260be23
Merge pull request #1395 from Hestia-Homes/fix/neighbour-divergence-fuel-cohort
neighbour_divergence: key cohorts on main-heating fuel
2026-07-01 15:49:38 +01:00
Daniel Roth
0488696df8
Merge pull request #1397 from Hestia-Homes/fix/1376-hhrsh-baseline-archetype
Add the HHRSH baseline archetype so it stops scoring as old storage (#1376)
2026-07-01 15:41:52 +01:00
Khalim Conn-Kowlessar
2f577c3ebc Re-map old-storage HHRSH overrides onto the high-heat-retention archetype 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:34:49 +00:00
Khalim Conn-Kowlessar
04484edc67 Re-map old-storage HHRSH overrides onto the high-heat-retention archetype 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:33:24 +00:00
Jun-te Kim
009394bb19 neighbour_divergence: key cohorts on main-heating fuel
The neighbour SAP-divergence cohort was (postcode, property_type, built_form),
which mixed electric- and gas-heated dwellings. Electricity scores materially
lower in SAP than mains gas for identical fabric, so a mixed-fuel postcode
produced cross-fuel false outliers — an electric dwelling flagged only for being
electric among gas neighbours.

Add the main-heating fuel class to the cohort key (electricity variants — 29/30
+ off-peak 31-40 — collapse to one class; every other code is its own bucket).
Now every flagged divergence is a same-fuel comparison worth investigating. On
portfolio 814 this refined 20 raw divergences to 17 same-fuel ones while keeping
the genuine within-fuel outliers (e.g. the all-electric WC2B 4AW flats at SAP
26/38 vs a cohort median of 67).

Reaches the fuel via epc_main_heating_detail through the indexed property_id —
still never touches the recommendation table. Surfaced by the portfolio-814
recommendation audit (Work item B, #1388).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:24:31 +00:00
Daniel Roth
baaadcdf98
Merge pull request #1392 from Hestia-Homes/fix/1376-water-heating-house-coal
Reclassify water-heating overrides off the house-coal dumping ground (#1376)
2026-07-01 15:19:39 +01:00
Khalim Conn-Kowlessar
51abd15289 Re-map house-coal water-heating overrides onto faithful biomass and immersion archetypes 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:59:44 +00:00
Khalim Conn-Kowlessar
ffbef2d047 Re-map house-coal water-heating overrides onto faithful biomass and immersion archetypes 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 13:58:39 +00:00
Daniel Roth
221e310fd8
Merge pull request #1382 from Hestia-Homes/incorrect-overrides
Fix HHRSH eligibility for on-gas-street electric dwellings; rename mains_gas → gas_connection_available
2026-07-01 14:53:14 +01:00
KhalimCK
9db8b60a54
Merge pull request #1384 from Hestia-Homes/fix/1376-glazing-proportion-reconcile
Defer aggregate-mix glazing overrides to the cert's per-window glazing (#1376)
2026-07-01 13:37:28 +01:00
Daniel Roth
90abcd9f54 Merge branch 'main' into incorrect-overrides 2026-07-01 12:30:15 +00:00
Khalim Conn-Kowlessar
0ebff1bcc2 Re-classify aggregate-mix glazing overrides flattened to Double onto MIXED 🟩
One-time script (dry-run default, --apply in a transaction, idempotent) reusing the
live glazing_mix_guard so the backfill and classifier cannot drift. Maps every
genuine percentage-mix override (neither type >= 90%) off a flattened single type
onto MIXED (no overlay -> the cert's per-window glazing is kept). property_overrides
TEXT updated now; the glazing pgEnum cache write for 'Mixed glazing' is deferred
until the FE adds the member. Dry-run against the audited DB reports 647 rows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:09:42 +00:00
Jun-te Kim
003defcf55 Add find-weird-recommendations skill + its two detectors
A focused sibling to audit-ara-portfolio: that skill audits baselines/plans/SAP;
this one audits the *recommendations themselves* — why a measure was or wasn't
offered. Motivated by the portfolio-814 review (Khalim's HHRSH-on-community-
heating, missing-HHRSH, missing-secondary-heating-removal, and a neighbour split).

Adds:
- .claude/skills/find-weird-recommendations/SKILL.md — scan -> neighbour scan ->
  live re-model deep-dive -> root-cause -> codify, with a seeded known-bug
  catalogue and the query-safety rules inherited from audit-ara-portfolio.
- scripts/audit/anomalies.py: new `plan-stops-short-of-goal` HIGH check — the
  default plan ends below the goal band on an unlimited-budget scenario (the
  deterministic worklist for "why didn't this get recommended X"). Adds
  scenario_budget to the bundle/query so budget-capped scenarios are excluded.
- scripts/audit/neighbour_divergence.py: groups a portfolio by (postcode,
  property_type, built_form) and flags effective-SAP outliers vs the cohort
  median. Never touches the 26m-row recommendation table, so it is safe
  portfolio-wide.
- Tests for both (12 passing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 11:06:03 +00:00
KhalimCK
9968e2b9df
Merge pull request #1379 from Hestia-Homes/fix/1376-flat-roof-insulation-thickness
Score flat roofs by their known insulation depth, not the age-band default (#1376)
2026-07-01 11:58:46 +01:00
Daniel Roth
a174301136 rename mains_gas to gas_connection_available 2026-07-01 10:50:58 +00:00
Khalim Conn-Kowlessar
32e296ca3f Re-classify flat-roof overrides with a known depth onto their thickness member 🟩
One-time script (dry-run default, --apply in a transaction, idempotent) mapping a
flat roof's stated depth (flat: Nmm) onto the nearest Table 16 rung member so the
overlay scores it by thickness, not the age-band default. Updates property_overrides
(TEXT) immediately; the roof_type pgEnum cache writes are deferred until the FE adds
the FLAT_*MM members. Dry-run against the audited DB reports 102 rows, deferring
Flat 50/100/150 mm.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 10:19:09 +00:00
Khalim Conn-Kowlessar
9af90aa718 Re-classify party-ceiling roof overrides mis-read as external roofs 🟩
One-time script (dry-run default, --apply in a transaction, idempotent) that maps
every party-ceiling override (another/same dwelling or premises above) currently
stored as an external roof value onto the party-ceiling member, reusing the live
roof_party_ceiling_guard so the backfill and the classifier cannot drift. Updates
property_overrides (TEXT, the modelling read path) and the roof classifier cache;
dry-run against the audited DB reports 106 rows. No FE migration — the party-
ceiling values already exist in the roof pgEnum.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 09:46:01 +00:00
Daniel Roth
db27a6153f
Merge pull request #1374 from Hestia-Homes/audit/bad-lodged-source-data
fix(audit): Class C — silence effective-lodged-divergence for implausible lodged scores (#1361)
2026-07-01 09:15:45 +01:00
Daniel Roth
7f63702295
Merge pull request #1369 from Hestia-Homes/audit/ara-newest-plan-guardrails
Guard the Ara portfolio audit against the 26m-row recommendation seq-scan
2026-07-01 08:52:27 +01:00
Daniel Roth
c73846b448 Merge branch 'main' into audit/bad-lodged-source-data 2026-07-01 07:49:21 +00:00
Daniel Roth
0c701ba3de
Merge pull request #1373 from Hestia-Homes/fix/1361-class-b-predicted-null-lodged
Drop the phantom Lodged Performance on predicted Properties (#1361 Class B)
2026-07-01 08:35:58 +01:00
Daniel Roth
db66b3b273
Merge pull request #1372 from Hestia-Homes/fix/1361-class-a-heating-classification-taxonomy
Fix PRD #1361 Class A: complete the landlord-heating classification taxonomy
2026-07-01 08:16:45 +01:00
Khalim Conn-Kowlessar
7e06aa63c6 Backfill the phantom Lodged Performance on predicted Properties to NULL 🟩
One-time script (dry-run default, --apply in a transaction, idempotent) that
NULLs the four lodged_* columns on every predicted-source baseline row — a
predicted EPC exists and no lodged one does — leaving Effective, the bill block,
and rebaseline_reason intact. Dry-run against the audited DB reports 12,236 rows.
Must run after the FE-owned Drizzle ALTER ... DROP NOT NULL lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 22:17:57 +00:00
Khalim Conn-Kowlessar
585c8b1501 One-time script to re-classify stale heating overrides
Deterministic catalogue remap (no LLM) that re-resolves the stored archetype for
the canonical RdSAP heating descriptions the under-populated taxonomy
mis-classified. Dry-run by default; --apply writes inside a transaction;
idempotent. Updates property_overrides.override_value (TEXT — what the modelling
reads, the actual band-G fix: 3,028 rows incl. 2,210 community boilers + 770
panel/convector room heaters). Cache (the Drizzle-owned main_heating_system
pgEnum) updates are deferred per-value until the FE-repo enum migration adds the
new archetypes — surfaced explicitly by the script.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 20:30:59 +00:00
Jun-te Kim
59508eb033 Add scripts/data_exports.py: principal-pitch export on the new DDD model
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>
2026-06-30 17:39:46 +00:00
Daniel Roth
afe1801273 implausible-lodged-score check fires for bad upstream EPC data (lodged < 13, gap >= 15) 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 15:27:19 +00:00
Daniel Roth
e70df63ee6 implausible-lodged-score check fires for bad upstream EPC data (lodged < 13, gap >= 15) 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 15:26:29 +00:00
Daniel Roth
fe1d04983b effective-lodged-divergence is silent for implausible lodged scores (< 13) 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 15:25:02 +00:00
Khalim Conn-Kowlessar
4a110d13cd Guard the portfolio audit against the 26m-row recommendation seq-scan
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>
2026-06-30 13:23:26 +00:00
Daniel Roth
71b304fa47 decrease lambda concurrency from 32 to 12 2026-06-29 13:32:53 +00:00
KhalimCK
29a0cc7f47
Merge pull request #1344 from Hestia-Homes/tooling/modelling-anomaly-audit
feat(audit): pluggable modelling-anomaly audit + audit-ara-portfolio skill
2026-06-29 11:18:26 +01:00
Khalim Conn-Kowlessar
02ef67fd8f chore(debug): summary_to_sap.py — Elmhurst Summary PDF -> our SAP + trail 🟪
Runs a Summary PDF through the chain-test path (pdftotext ->
ElmhurstSiteNotesExtractor -> from_elmhurst_site_notes) into Sap10Calculator
and dumps SAP + per-end-use kWh + the intermediate worksheet trail, for
diffing our calc against the accompanying Elmhurst U985 worksheet PDF.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-28 21:26:30 +00:00
Khalim Conn-Kowlessar
2d6b078bd8 feat(audit): self-improvement loop in the skill + provenance convention 🟩
Add Phase 6 (self-improve) to audit-ara-portfolio: when a run confirms a
novel systematic problem, codify it as a check — gated on systematic (>=5
props, root-caused), not-already-covered, and /grill-me-pressure-tested.
Each check records provenance (motivating cause + example properties) so the
registry stays sharp and compounds every run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:57:57 +00:00
Khalim Conn-Kowlessar
e3c9107313 feat(audit): --scenario filter + audit-ara-portfolio skill 🟩
Script takes an optional --scenario to restrict to one scenario's plans. New
skill drives the full loop: run the deterministic scan, review groups,
deep-dive samples via run_modelling_e2e, characterise sub-classes, and
cross-reference open PRs/ADRs — then proposes new checks to codify.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:49:48 +00:00
Khalim Conn-Kowlessar
37c7a2c186 feat(audit): solar + high-SAP checks; group under scripts/audit/ 🟩
Add recommendation-level rollups (solar SAP points + solar bill saving) and
checks: impossible-sap-over-100 (found 1), excessive-solar-sap (oversized
array, 51), low-solar-bill-savings (SEG/self-consumption pricing, 83),
unusually-high-post-sap (21). Move to scripts/audit/anomalies.py
(python -m scripts.audit.anomalies).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:46:23 +00:00
Khalim Conn-Kowlessar
39fd1c9e42 feat(audit): pluggable modelling-anomaly audit over the DB 🟩
A check-registry that reads property/baseline/plan/scenario and flags odd
results (plan-below-baseline, already-meets-goal-with-works, band/score
mismatch, zero-works-post-differs, effective-lodged divergence, negative
bill savings). Writes modelling_audit.md/.csv. Adding a check = one
decorated function.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:38:28 +00:00
Daniel Roth
7f552edc0d pass scenario id to already processed check 2026-06-26 11:32:17 +00:00
Daniel Roth
f811b39fa1 correct previous comits 2026-06-26 11:26:28 +00:00
Daniel Roth
632465f03f allow for multiple scenarios for 1 portfolio without ignoring all properties in second scenario 2026-06-26 11:24:26 +00:00
Daniel Roth
17a9f0aafc refetch_epc=False skips API entirely; EPC-less properties go straight to prediction path
When refetch_epc=False and no stored lodged EPC exists, the handler no longer
falls back to a live EPC API call — it treats the property as EPC-less and
hands it to the prediction path. This keeps REFETCH_EPC (lodged path) and
REPREDICT_EPC (prediction path) cleanly independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 10:24:27 +00:00
Daniel Roth
b1fd9d9368 Clarify REFETCH_EPC/REPREDICT_EPC comments — both flags skip-if-stored, not never-fetch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 10:20:29 +00:00
Daniel Roth
5c3bde0cf5 Update trigger script and local invoker to use refetch_solar, refetch_epc, repredict_epc 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 10:17:20 +00:00
Khalim Conn-Kowlessar
3f69c4be02 docs: full-SAP baseline-downgrade follow-ups + Case A population sweep tool
Captures the calc-facing ventilation-type gap (older RdSAP mappers drop
mechanical_ventilation_kind), the FE-side Main Fuel display, the sweep survivor
clusters, and the predicted-property display path — all separate from ADR-0037.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:45:44 +00:00
Jun-te Kim
25fb0a9ebb Batch postcode groups into SQS messages for modelling_e2e
Group pending property IDs by postcode and pack them into ~BATCH_SIZE
messages, never splitting a postcode, so each SQS message drives one
batched modelling_e2e Lambda invocation. Adds a completed-since skip
filter and a properties cap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 10:21:17 +00:00
KhalimCK
f7f74ea72b
Merge pull request #1288 from Hestia-Homes/feature/per-cert-mapper-validation
Feature/per cert mapper validation
2026-06-24 12:04:00 +01:00
Khalim Conn-Kowlessar
aad4050915 fix(hyde): harden Elmhurst browser automation for the dev container
In-container Playwright runs were flaky: the chromium renderer crashed
mid-build ("Target crashed") on the 64M /dev/shm, and login intermittently
hung. Added `--disable-dev-shm-usage` + `--no-sandbox` launch args, a
4-attempt login retry loop (domcontentloaded + explicit selector wait),
and an `ELM_GUID` env override so a per-UPRN assessment can be targeted
without editing the module. Tooling only — no calculator impact.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 19:46:41 +00:00
Jun-te Kim
390da1e491 resolve merge conflicts 2026-06-23 18:09:09 +00:00