Commit graph

6909 commits

Author SHA1 Message Date
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
de7fb94ff7 docs(adr): record nearby-postcode broadening (0034) + share HTTP retry primitive
Closes out the cohort-broadening work with its decision record and consolidates
the retry plumbing.

ADR-0034 documents broadening the EPC-Prediction cohort to the real unit
postcodes nearest the target (via postcodes.io) when its own postcode holds no
same-type comparable — extending ADR-0031 decision 5. Records why postcodes.io
was chosen over council[] (whole-LA, no property_type in rows), a bulk Code-Point
Open / ONSPD dataset, and the OS Places radius API, and the lazy / nearest-first
early-stop / soft-fail policy. Broadening-specific docstrings now cite 0034.

Retry consolidation: extract the EPC client's call_with_retry into a shared
infrastructure/http_retry.py keyed off a generic TransientHttpError marker, so
the mechanism (exponential backoff, Retry-After) is shared while each client
keeps its own transient policy. EpcRateLimitError now subclasses TransientHttpError
(still an EpcApiError); PostcodesIoClient routes through the same helper, raising
TransientHttpError on 429/5xx and soft-failing to the seed once exhausted (the EPC
client propagates instead). Direct tests for the shared helper; EPC + postcodes.io
suites repointed at the shared sleep.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 16:54:06 +00:00
Daniel Roth
a76666926f
Merge pull request #1274 from Hestia-Homes/trigger-e2e-locally
Limit database connections using NullPool
2026-06-23 17:42:22 +01:00
Daniel Roth
93f6fbe1b9 revert pytest.ini 2026-06-23 16:39:49 +00:00
Daniel Roth
a4aaf0e81f Merge branch 'main' into trigger-e2e-locally 2026-06-23 16:38:03 +00:00
Daniel Roth
79a76b10a9 fix db issues 2026-06-23 16:36:59 +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
d4c120ede7
Merge pull request #1271 from Hestia-Homes/feature/task-handler-clean
Feature/task handler clean
2026-06-23 16:47:33 +01:00
Jun-te Kim
a7d3e00178 32 2026-06-23 15:42:00 +00:00
Jun-te Kim
119ff3740c fix(task_handler): persist cloud_logs_url for modelling_e2e
@task_handler never built or passed cloud_logs_url, so every app using
it (incl. modelling_e2e) ran run_subtask with the None default and the
CloudWatch deep-link was never saved onto the SubTask. @subtask_handler
did this correctly.

Extract the URL builder into a shared utilities/aws_lambda/cloud_logs.py
(public cloudwatch_url()), use it from both handlers, and pass the URL
into run_subtask from @task_handler. Add regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 15:42:00 +00:00
Daniel Roth
4e3eb52a37
Merge pull request #1268 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
Feature/hyde make it more accurate with tests
2026-06-23 16:08:05 +01:00
Jun-te Kim
5737923622 32 and delete in plan 2026-06-23 15:01:34 +00:00
Jun-te Kim
6ee2f6257a fix(mapper): close modelling_e2e cohort mapping gaps (built_form, PV-list, windows-dict)
Closes the mapper-coverage gaps surfaced by the modelling_e2e prediction-cohort
failures (portfolio 796):

- built_form (SAP-16.0): derive from dwelling_type in _normalize_sap_schema_16_x
  (Mid-terrace->4, End-terrace->3, Semi-detached->2, Detached->1; flats->modal 4).
  ML-only field (SAP calc never reads it) so SAP- and gate-neutral. 5 flat certs
  that omitted built_form now map.
- photovoltaic_supply as a measured-array LIST: routed all pre-21 RdSAP mappers
  (17.0/17.1/18.0/19.0/20.0.0) through _map_schema_21_pv, whose list branch is now
  dict-tolerant (_pv_array_field reads dict OR dataclass). They capture the PV
  arrays like 21.0.x instead of raising "'list' object has no attribute
  none_or_no_details" and sinking the whole cohort.
- windows-as-dict (16.x): handled in the normalizer (not just windows-as-list).

Genuinely-sparse certs (omit door_count/habitable/glazed_area) remain fail-loud;
the gate-regressing multiple_glazed_proportion default and the recursive
RdSAP-21.0.0 ADR-0028 alignment are left fail-loud + flagged for review (worklist).

+5 regression tests; component-accuracy gate 26/26; 0 new pyright errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 14:51:40 +00:00
Daniel Roth
f09f01adbf
Merge pull request #1266 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
test for 16
2026-06-23 15:20:17 +01:00
Jun-te Kim
c12bfc7413 test for 16 2026-06-23 14:11:30 +00:00
Daniel Roth
cbc14f1ca2 better tracking of already processed properties 2026-06-23 14:09:59 +00:00
Daniel Roth
aa92ffaac1 Merge branch 'main' into trigger-e2e-locally 2026-06-23 13:41:29 +00:00
Jun-te Kim
3c45a30890
Merge pull request #1264 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
Feature/hyde make it more accurate with tests
2026-06-23 14:31:45 +01:00
Jun-te Kim
2b0cb180bf update air permebility 2026-06-23 13:21:31 +00:00
Jun-te Kim
60ec922430 fix regression tests 2026-06-23 13:17:23 +00:00
Jun-te Kim
666cf30437 gated propertly 2026-06-23 13:16:34 +00:00
Jun-te Kim
22b92f968e
Merge pull request #1263 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
data types
2026-06-23 13:50:45 +01:00
Jun-te Kim
00af7b5a54 data types 2026-06-23 12:42:53 +00:00
Daniel Roth
f20646d774 missing files 2026-06-23 12:25:52 +00:00
Daniel Roth
901b74ae7c udpate 2026-06-23 12:25:43 +00:00
Jun-te Kim
1a080254e7
Merge pull request #1261 from Hestia-Homes/feature/e2e-runs
Feature/e2e runs
2026-06-23 12:24:18 +01:00
Khalim Conn-Kowlessar
c3422704f5 revert epc timeout to 10s 2026-06-23 11:19:23 +00:00
Khalim Conn-Kowlessar
52e5a4d402 Merge remote-tracking branch 'origin/main' into feature/e2e-runs 2026-06-23 11:05:15 +00:00
Khalim Conn-Kowlessar
efaff228ac feat(scripts): add --from-db re-model path + raise EPC API timeout
- run_modelling_e2e --from-db re-models from already-persisted inputs (reads
  each Property's Effective EPC + planning protections + solar from the DB) and
  skips every live fetcher — zero gov-API calls. With --persist it re-writes the
  Plan and, for lodged-EPC Properties, the Baseline. Self-contained loop; the
  live-fetch path is untouched. Makes local re-runs instant and avoids tripping
  the gov API's per-IP rate limit (6000 req / 5 min) during iteration.
- EpcClientService.REQUEST_TIMEOUT 10s -> 30s: a cold per-UPRN search can exceed
  10s and the old timeout turned it into a timeout-then-retry; 30s rides it out.

Note: an open perf question remains — modelling is fast in isolation (<0.5s/
property) but a long-lived --persist run shows ~1 min/property; suspected in the
persist path (plan.save / baseline) or connection handling, NOT the API. Left
mid-diagnosis for handover.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 11:05:06 +00:00
Daniel Roth
ad86f34701
Merge pull request #1259 from Hestia-Homes/e2e-modelling-handler-returns-taskid
Task Handler handler returns task ID and subtask ID. Also remove broken recommendation
2026-06-23 11:41:38 +01:00
Daniel Roth
c49e1f60a2 dont consider system tune up recommendations - causes error 2026-06-23 10:36:27 +00:00
Daniel Roth
0a3b827be2 task handler returns task and subtask IDs 2026-06-23 10:33:38 +00:00
Daniel Roth
2c8a8358b4
Merge pull request #1258 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
updated sap scaema to take in inputs
2026-06-23 11:30:40 +01:00
Daniel Roth
78c358d5e8 tweak script to use provided input. track output in md file 2026-06-23 10:27:39 +00:00
Jun-te Kim
210ca6397f updated sap scaema to take in inputs 2026-06-23 10:22:40 +00:00
Daniel Roth
95d6ee1a33
Merge pull request #1256 from Hestia-Homes/feature/deploy-e2e-modeller
Actually deploy e2e modelling lambda
2026-06-23 09:51:41 +01:00
Daniel Roth
e949490b20 actually deploy lambda 2026-06-23 08:46:23 +00:00
Daniel Roth
04aa5db1e2
Merge pull request #1253 from Hestia-Homes/feature/trigger-e2e-lamnda
e2e lambda
2026-06-23 09:40:27 +01:00
Daniel Roth
625edbefa4 trigger workflows 2026-06-23 08:26:19 +00:00
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
Khalim Conn-Kowlessar
564a2ee78f Merge remote-tracking branch 'origin/main' into feature/e2e-runs
# Conflicts:
#	scripts/run_modelling_e2e.py
2026-06-23 07:49:22 +00:00
Daniel Roth
6b8eb88a38 increase lambda timeout to maximum 2026-06-22 16:17:30 +00:00
Daniel Roth
f1a2bbc467 list of properties when triggering locally 2026-06-22 16:13:10 +00:00
Daniel Roth
25c695186b measured excluded plus get geospatial nearby stuff working 2026-06-22 16:12:16 +00:00
Daniel Roth
7e5af6c8f4 process multiple properties in one message 2026-06-22 15:46:18 +00:00
Daniel Roth
5ecb47d46c Merge branch 'main' into feature/trigger-e2e-lamnda 2026-06-22 14:55:16 +00:00
Daniel Roth
2156109e99 concurrency = 2 2026-06-22 14:54:23 +00:00
Daniel Roth
94debe57be
Merge pull request #1254 from Hestia-Homes/feature/hyde_make_it_more_accurate_with_tests
neighbouring properties added
2026-06-22 15:54:08 +01:00
Daniel Roth
233dace245 2 concurrent executions 2026-06-22 14:49:28 +00:00