Commit graph

10 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
0c70280dea guard(modelling_e2e): quarantine predicted Properties the calculator mis-scores
TEMPORARY guard (remove once the SAP calculator's oil-heating under-score is
fixed): a predicted oil-boiler picture scores SAP 13/G against its own
synthesised recorded SAP of 50/E, so the optimiser overshoots goal C all the
way to band A and publishes nonsense.

A predicted EpcPropertyData carries its recorded SAP (energy_rating_current).
When the calculator baseline diverges from it by more than ~one band (20 SAP
points), withhold the Plan: raise inside the per-property loop so the existing
failure isolation drops just that property into `failures` and fails the
subtask, while every other property still models and persists. Lodged
Properties are untouched — they have a real recorded cert and the Rebaseliner
already owns this check.

Verified end-to-end against property 713406 (UPRN 100061849247): baseline 13.2
vs recorded 50 -> quarantined, no Plan written.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 09:07:24 +00:00
Jun-te Kim
22cb47a280
Merge pull request #1285 from Hestia-Homes/feature/e2e-runs
fix(modelling_e2e): persist predicted EPC + baseline for predicted pr…
2026-06-24 09:08:06 +01:00
Jun-te Kim
af5b2b5f80 Mark unmappable cohort certs as a subtask failure
Skipped cohort certs were previously surfaced only as outputs.result on a
completed subtask, so they were easy to miss. Treat them as a failure too:
once the batch has run to completion (so every modellable property is already
written to DB), raise if there were any per-property errors OR any skipped
certs. The run gets flagged for debugging without discarding the work done.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 18:03:04 +00:00
Khalim Conn-Kowlessar
e80be44fd1 fix(modelling_e2e): persist predicted EPC + baseline for predicted properties
A predicted Property (no lodged EPC) got a Plan but nothing else: the synthesised
EPC was never written to epc_property, and Baseline Performance was skipped — so
property 729529 (portfolio 796 / scenario 1268), predicted from its DA16 1QZ
cohort, was "missed" with no predicted-EPC row and no baseline row.

Persist the synthesised EPC in the predicted slot (uow.epc.save(..., source=
"predicted"), ADR-0031) inside the Plan UoW, then run the Baseline orchestrator
for predicted Properties too — it re-hydrates the predicted EPC and establishes
the baseline from it. The earlier "lodged only" guard is dropped: by the write
block the Property always has a persisted EPC (lodged or predicted); one that
could be neither fetched nor predicted raised earlier.

Verified against the DB by invoking the real handler for 729529: predicted
epc_property rows 0->1 and property_baseline_performance rows 0->1. Baseline on
the predicted picture builds cleanly (RHI present, reason pre_sap10). Tests
updated: prediction + broadening paths now assert the predicted-slot epc.save and
the baseline run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 17:49:08 +00:00
Khalim Conn-Kowlessar
2ee1b35dca fix(modelling_e2e): persist Baseline Performance for lodged properties
The handler wrote epc/spatial/solar/plan and marked the property modelled, but
never established its Baseline Performance — so no row was created in
property_baseline_performance for any property modelled through the Lambda
(noticed on portfolio 796 / scenario 1268 / property 727218, a lodged property).

Mirror the e2e runner: after the plan UoW commits (so the EPC is persisted for
the orchestrator to re-hydrate), run PropertyBaselineOrchestrator for lodged
properties. Predicted properties have no lodged figures and no persisted EPC, so
they are skipped — consistent with the e2e runner and the ara_first_run Baseline
stage.

Verified 727218's baseline pipeline builds end-to-end in-memory (lodged_performance
→ CalculatorRebaseliner → bill → PropertyBaselinePerformance, reason pre_sap10).
Tests: lodged path asserts the orchestrator runs once; prediction path asserts it
does not.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 17:21:03 +00:00
Khalim Conn-Kowlessar
4f4ec32e51 Merge remote-tracking branch 'origin/main' into feature/e2e-runs
# Conflicts:
#	repositories/comparable_properties/epc_comparable_properties_repository.py
#	tests/repositories/comparable_properties/test_epc_comparable_properties_repository.py
2026-06-23 17:07:27 +00:00
Khalim Conn-Kowlessar
0bd2db4f03 feat(modelling_e2e): price gap measures via overlay + broaden prediction to nearby postcodes
Two reconciliations to make the modelling_e2e Lambda handler production-ready.

1. Price through the off-catalogue overlay, drop the workarounds
   The handler priced through a plain ProductPostgresRepository and excluded
   secondary_heating_removal / system_tune_up / system_tune_up_zoned to dodge
   ProductNotFound (and a poisoning pgEnum DataError). Those measures are now
   priced by catalogue_with_off_catalogue_overrides (already used by the e2e
   runner and PostgresUnitOfWork), so the exclusions are removed and ALL measure
   types are considered. This also fixes gas-boiler / single-glazed properties,
   which Dan's handler never excluded and so still crashed (the standard
   system_tune_up option is built unconditionally — the considered-measures
   exclusion never actually gated it).

2. Broaden the EPC-Prediction cohort to nearby real postcodes (ADR-0031)
   A property with no lodged EPC and no same-type comparable in its own postcode
   (e.g. the only flat among houses) used to gate out and fail the subtask. The
   gov EPC API cannot search by radius/outcode, so we resolve the real unit
   postcodes physically nearest the target via postcodes.io (keyless; already a
   trusted in-repo dependency) and walk them nearest-first until enough same-type
   comparables surface. New PostcodesIoClient (transient-failure retry with
   exponential backoff, soft-failing to the seed so broadening never breaks
   prediction) and EpcComparablePropertiesRepository.candidates_near. Wired into
   the handler and e2e runner; broadening is lazy (only on gate-out) and memoised
   per (postcode, property_type).

Validated live: property 728476 (gas boiler) prices system_tune_up at GBP295;
property 718580 (lone flat in BR6 6BS) now predicts via nearby BR6 postcodes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:25:18 +00:00
Jun-te Kim
00af7b5a54 data types 2026-06-23 12:42:53 +00:00
Khalim Conn-Kowlessar
c3422704f5 revert epc timeout to 10s 2026-06-23 11:19:23 +00:00
Daniel Roth
7e5af6c8f4 process multiple properties in one message 2026-06-22 15:46:18 +00:00