Commit graph

716 commits

Author SHA1 Message Date
Daniel Roth
fad7bd6e96
Merge pull request #1363 from Hestia-Homes/fix/hyde-portfolio-audit
fix(full-sap): seven mapper/overlay fixes from the portfolio-796 modelling audit
2026-06-30 10:26:17 +01:00
Khalim Conn-Kowlessar
2c851e9e5e Re-baseline pins for full-SAP PV + tariff mapper fixes 🟩
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>
2026-06-30 09:18:39 +00:00
Khalim Conn-Kowlessar
e3c023e0f6 Preserve an existing more-off-peak cert meter under a heating overlay 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 20:00:41 +00:00
Khalim Conn-Kowlessar
da17ddce8f Stop a System-built landlord override being mis-read as a basement 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:30:25 +00:00
Khalim Conn-Kowlessar
4e96ea91a5 Assume a dual Economy-7 meter for all-electric room-heater dwellings 🟩
Electric room heaters (691) get a Dual meter from the overlay (not single-rate):
an all-electric room-heater dwelling realistically bills on Economy 7, and the
§12 dispatch then applies a high/low split rather than a single-rate over-penalty.
Overlay owns its assumed-meter policy via _ASSUMED_DUAL_METER_CODES (the §12
off-peak systems + room heaters), keeping OFF_PEAK_IMPLYING_HEATING_CODES pure.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:18:13 +00:00
Khalim Conn-Kowlessar
13f1981776 Assume a dual Economy-7 meter for all-electric room-heater dwellings 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:15:48 +00:00
Khalim Conn-Kowlessar
2b0b7eff91 Add Electric room heaters as a canonical landlord heating archetype 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:00:36 +00:00
Daniel Roth
085bd29af4
Merge pull request #1359 from Hestia-Homes/fix/heat-pump-flow-temp-efficiency
fix(sap): heat-pump PSR-extension + water-heating 100% floor (Appendix N)
2026-06-29 16:59:47 +01:00
Khalim Conn-Kowlessar
ce59413f46 Map landlord electric room heaters to the direct-acting room-heater SAP code 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:58:34 +00:00
Khalim Conn-Kowlessar
8914496456 test(accuracy): ratchet after HP water-heating 100% floor 🟪
The Appendix N3.7 water-heating 100% floor drops corpus MAE 0.726 -> 0.721
and lifts within-0.5 74.1% -> 74.2% on the 1000-cert RdSAP-21.0.1 sample
(cert 100110101713 moves inside +-0.5). Tighten the MAE ceiling to 0.722 and
the within-0.5 floor to 0.742, and log the slice.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:40:53 +00:00
Daniel Roth
c202f15d8c fix broken unit tests 2026-06-29 15:40:22 +00:00
Khalim Conn-Kowlessar
672e6679c8 test(hp): floor heat-pump water-heating efficiency at 100% (App N3.7) 🟥
SAP 10.2 Appendix N3.7 ("Thermal efficiency for water heating - heat pumps",
PDF p.109): "multiply the thermal efficiency for water heating by the in-use
factor in Table N8; subject to a minimum efficiency of 100%." Our
_heat_pump_apm_efficiencies applies the in-use factor but omits the floor.

Anchored to golden fixture case 56 (PCDB 100061, cert 100110101713): an
oversized HP (PSR 3.107) extends water,3 198.9% -> 128.55%, x 0.60 in-use =
77.13% < 100% -> the accredited Elmhurst worksheet (216) reads 100.0000, we
read 77.13%. In-range PSR keeps 0.60 x 198.9 = 119.34% (above the floor).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:33:04 +00:00
Khalim Conn-Kowlessar
2d6479536c test(accuracy): ratchet SAP MAE 0.740 -> 0.726 after HP PSR-extension 🟪
The heat-pump PSR-extension fix (SAP 10.2 Appendix N2) drops corpus MAE from
0.740 to 0.726 on the 1000-cert RdSAP-21.0.1 sample; within-0.5 holds at
74.1%. Tighten the ceiling and log the slice.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:16:07 +00:00
Khalim Conn-Kowlessar
3d93c7b7d5 test(pcdb): PSR-extension toward 100% above largest / below smallest 🟥
SAP 10.2 Appendix N2 (PDF p.101, footnote 44/45): for an air/ground/water
source heat pump whose plant size ratio exceeds the record's largest PSR,
the efficiency is reciprocal-interpolated between the largest-PSR value and
100% at twice the largest PSR (100% beyond that); below the smallest PSR the
efficiency is 100%. Our interpolator instead clamps to the top/bottom row.

Anchored to the accredited Elmhurst worksheet for cert 100110101713 (golden
fixture case 56, PCDB 100061): PSR 3.10665 over the record's largest 2.0
gives eta_space,1 = 147.011 -> (206) = 0.95 x 147.011 = 139.660, vs the
clamped 352.0 -> 334.4% that over-rates the dwelling by +18 SAP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:08:15 +00:00
Daniel Roth
46ca714ef9 Batch plan saves reduce RDS CPU during bulk modelling runs 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:06:47 +00:00
Daniel Roth
9c6b477025 Batch plan saves reduce RDS CPU during bulk modelling runs 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 15:04:54 +00:00
Daniel Roth
9f0dd067f8 Merge branch 'main' into feature/batch-save-and-delete-epc 2026-06-29 14:38:57 +00:00
Khalim Conn-Kowlessar
9927169e23 test(accuracy): ratchet SAP gauge after PV connection gate 🟪
within-0.5 floor 0.73->0.74 (now 0.741), MAE ceiling 0.762->0.740 (now
0.7397) on the fixed RdSAP-21.0.1 corpus. Log entry appended.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 13:43:30 +00:00
Khalim Conn-Kowlessar
8606cab5f0 fix(pv): credit PV only when connected to the dwelling's meter 🟩
Gate PV generation/credit in cert_to_inputs on gov-API pv_connection:
credit only when ==2 ('connected'); ==1 ('present but not connected to the
dwelling's meter') contributes zero to the dwelling's cost/CO2/PE per
RdSAP 10 §11.1 / SAP 10.2 Appendix M. Non-int (None / site-notes str) keeps
the credit-if-array behaviour, so the Elmhurst/Summary + synthetic paths are
unchanged (no regression).

Corpus: all 5 pv_connection=1 PV certs move inside ±0.5 (e.g. 100051118081
+6.5→+0.5); MAE 0.760→0.740, within-0.5 73.8→74.3%, no regression
(pv_connection=2 certs keep their credit).

Also corrects a now-load-bearing latent bug: the solar-recommendation
overlay tagged recommended arrays pv_connection=1 ('not connected') — which
the new gate would zero. A new install connects to the dwelling's meter, so
it must be 2; pinned by the overlay test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 13:40:51 +00:00
Khalim Conn-Kowlessar
775232b4e7 test(pv): credit PV only when connected to dwelling meter (pv_connection) 🟥
RdSAP 10 §11.1 / SAP 10.2 Appendix M: PV is included in a dwelling's
assessment only if connected to the dwelling's own electricity meter. The
gov-API pv_connection enum encodes this — 0=no PV, 1=present-but-not-
connected, 2=connected. Corpus-validated (57 PV certs: pv_connection=1 MAE
4.48->1.22 without credit, 0/5 need it; pv_connection=2 needs it, MAE 0.98
vs 10.29) and Elmhurst-proven (connected SAP 87 vs not-connected 74).

cert_to_inputs currently credits a pv_connection=1 array; the test pins that
it must contribute zero generation. Adds pv_connection to make_minimal_sap10_epc.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 13:32:20 +00:00
Daniel Roth
f27d1e21bb Batch EPC writes in EpcPostgresRepository pass pyright strict 🟪
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 13:17:29 +00:00
Daniel Roth
0fa1b9001c Batch EPC writes in _flush_writes: two save_batch() calls instead of N save() calls 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 13:09:56 +00:00
Daniel Roth
fe69bccf22 Batch EPC writes via save_batch() on EpcPostgresRepository 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 12:19:49 +00:00
KhalimCK
98ba8d89dc
Merge pull request #1343 from Hestia-Homes/fix/effective-baseline-overrides-and-epc-fidelity
fix(baseline): honour EPC + overrides as the authoritative Effective baseline
2026-06-29 11:19:52 +01:00
KhalimCK
31e8b93ea0
Merge pull request #1345 from Hestia-Homes/fix/storage-heater-space-heating-demand
fix(sap): expose roof for mislabelled top-floor flats via roof_insulation_location
2026-06-29 11:18:03 +01:00
Khalim Conn-Kowlessar
23245a085c test(elmhurst): party-ceiling BP window is vertical, not a rooflight 🟥
_is_elmhurst_roof_window mis-routes a vertical window (Location "External
wall") to sap_roof_windows when the building part's roof is a PARTY ceiling
(A "Another dwelling above" / NR "Non-residential space above"). A party
ceiling has no external roof, so it cannot host a rooflight.

Surfaced by simulated case 53 (cert 000565 re-keyed as a mid-floor electric-
storage flat, roof "A Another dwelling above"): its External-wall window
(U 2.00) routed to sap_roof_windows -> window area not deducted from the wall
(wall over-counted ~7 W/K) + priced as a roof window -> our SAP 74.0 vs
Elmhurst worksheet 75. Elmhurst lodges it Type "Window", Location "External
wall".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-27 07:06:04 +00:00
Khalim Conn-Kowlessar
0f79de7a35 fix(exposure): honour determined roof_insulation_location for flats 🟩
A gov-API flat can lodge dwelling_type="Mid-floor flat" while carrying its
own exposed roof — a top-floor flat mislabelled mid-floor. _dwelling_exposure
keyed roof exposure on the dwelling_type label alone, dropping the roof
heat-loss term: space-heating demand under-read ~32%, SAP over-read +7.

Fix: when the main building part lodges a *determined* roof_insulation_location
(an RdSAP integer code, not the "ND" Not-Defined party-ceiling sentinel),
expose the roof regardless of a contradictory label. Structured field, not a
description string and not roof_construction (which the gov-API lodges
building-wide on every unit, so it is not a per-unit signal).

On the RdSAP-21.0.1 corpus roof_insulation_location separates the classes with
zero disagreement: all 190 party-ceiling flats lodge "ND"; the 4 mid/ground
flats this exposes all move toward lodged, 0 away. within-0.5 73.3% -> 73.6%,
MAE 0.774 -> 0.761 (ratchets tightened). Verified end-to-end on the same
block: 715363 (location 6, RHI 2694) 81 -> 74 = lodged; genuine mid-floor
sibling 715395 (location ND, RHI 1024) stays party at 83 = lodged.

The override is additive (only ever exposes a label-dropped roof) and reads
the main part, so multi-part flats with a party main ceiling stay party.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 21:34:33 +00:00
Khalim Conn-Kowlessar
7a74aaecb9 test(exposure): mid-floor-labelled flat with a lodged exposed roof 🟥
A gov-API cert can lodge dwelling_type="Mid-floor flat" while carrying a
real exposed roof element (roof_construction != 7 "dwelling above") over a
"(another dwelling below)" floor — i.e. a top-floor flat mislabelled
mid-floor. Property 715363 (uprn 6027561) + sibling 715395 (6027563) do
exactly this; the correctly-labelled top-floor sibling 715871 (6027574),
same block + same flat roof, already computes the lodged SAP 74.

_dwelling_exposure keys roof exposure on the dwelling_type label alone, so
it drops the roof heat-loss term, under-reading space-heating demand ~32%
(calc 1833 vs lodged RHI 2694) and over-reading SAP +7 (81 vs 74).

Pins the fix: a mid-floor label + lodged exposed roof must expose the roof
(floor stays party). Also corrects the existing mid-floor fixture to lodge
the party-ceiling code 7 (the default 4 is an exposed pitched roof).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 20:59:31 +00:00
Khalim Conn-Kowlessar
c776341e03 test: portfolio-796 override-rebaseline regression (the 7 properties) 🟩
Pin the hit-list properties: each property's real Landlord Override set still
resolves to overlays and trips physical_state_changed, and the rebaseliner
adopts the calculator output (reason physical_state_changed/both) rather than
echoing the lodged headline — so the displayed baseline and the modelled plan
agree. Scores a real cert through the live Sap10Calculator.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:22:32 +00:00
Khalim Conn-Kowlessar
4d5504fa10 feat: thread physical-state-change signal into rebaselining 🟩
Add Property.physical_state_changed (true on Site Notes / Landlord Overrides
/ Prediction — trigger (b)/(c)) and pass it from the
PropertyBaselineOrchestrator into the Rebaseliner. So an overridden or
predicted SAP>=10.2 property now stores calc(effective) as its Effective
baseline instead of echoing the lodged headline — closing the "81 in the DB"
divergence between the displayed baseline and the modelled plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:15:11 +00:00
Khalim Conn-Kowlessar
1e019ea3b3 test: rebaseliner adopts calc output when physical state changed 🟥
A SAP>=10.2 cert whose physical state was changed by Landlord Overrides or
Prediction must rebaseline off the calculator (the accredited lodged figure
no longer describes the dwelling) and tag physical_state_changed / both, and
must NOT log divergence (the calc IS adopted, nothing to validate against).
This is the D1 fix: the stored Effective baseline stops echoing the lodged
headline for overridden properties.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 19:04:32 +00:00
Khalim Conn-Kowlessar
6faa5171af feat: reconstruct top-level extract_fans_count from its persisted mirror 🟩
The deterministic calculator reads sap_ventilation.extract_fans_count (which
already round-trips); the top-level epc.extract_fans_count is its mirror (the
mapper sets both from one source). Reconstruct it from the same column so
EpcPropertyData round-trips complete, dropping the allow-list exception.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 18:54:43 +00:00
Khalim Conn-Kowlessar
5c4a8d9094 test: 7 calculator-read EPC fields must round-trip 🟥
community heating fuel + CHP fraction, alt-wall is_sheltered, wall
insulation thermal conductivity, pv_diverter_present, measured cylinder
volume, AP50 air permeability — all calculator-read, all silently dropped on
save. FE columns now live; assert deep-equal round-trip and drop their
coverage-guard allow-list entries so the guard enforces reconstruction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 18:42:51 +00:00
Khalim Conn-Kowlessar
bb4f8577fe test: correct multi-measure plan expectation for exposed-floor fix 🟩
The fixture lodges is_exposed_floor=True, which was silently dropped on
save->reload before this branch — so the orchestrator (reads the DB) modelled
the floor as not-exposed. Now it round-trips, the exposed floor is honoured,
and the ASHP-led max-gain fallback on this gas dwelling is bill-neutral
(marginally negative) rather than bill-positive: large energy saving, but the
gas->electricity fuel switch offsets the GBP saving. Same optimal package,
same telescoping; only the bill-savings sign assumption changed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:58:48 +00:00
Khalim Conn-Kowlessar
68055364a6 test: recursive persistence-coverage guard sees nested fields 🟪
The ADR-0036 guard only inspected EpcPropertyData's top-level fields, so a
dropped field on a NESTED object (the PV-array list, the floor heat-loss
flags) slipped straight through. Generalise it to walk every domain
dataclass reachable from EpcPropertyData and check each field is
reconstructed by a _compose/_to_* mapper or allow-listed (per-field or
whole-class), keyed by Class.field.

Surfaced 14 pre-existing nested gaps the old guard was blind to: 7 are
calculator-read with no FE column (scoring-relevant silent-drop, same class
as the PV bug — tracked follow-up), the rest dormant or awaiting FE tables.
Each is now explicit and justified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:53:04 +00:00
Khalim Conn-Kowlessar
1041c8ed0e test: solar PV arrays must round-trip through persistence 🟥
sap_energy_source.photovoltaic_arrays has no table, so every array is
dropped on save — worth ~12 SAP points on an electrically-heated dwelling
(persist != score). Inject two ordered arrays onto a PV-free fixture.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:43:26 +00:00
Khalim Conn-Kowlessar
c04692f9f5 test: floor-dimension heat-loss flags must round-trip 🟥
is_exposed_floor / is_above_partially_heated_space have no
epc_floor_dimension column, so a True flag round-trips back to the False
default and silently flips the floor's heat-loss path (persist != score).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 16:39:25 +00:00
KhalimCK
6303343575
Merge pull request #1341 from Hestia-Homes/fix/coherent-gas-boiler-overlay
fix(overlay): coherent gas-boiler heating system on Landlord Override
2026-06-26 14:18:56 +01:00
Jun-te Kim
a680d65188 fix(overlay): synthesise a coherent gas-boiler heating system on Landlord Override
A Landlord heating-system override was applied as a sparse patch, so the
replaced system's fields bled through. A storage flat reclassified as a gas
combi (property 728513) kept mains_gas=False, heating category 7, the 2401
storage charge control, a Dual meter and an electric-immersion cylinder — an
incoherent record that gated out the gas-boiler-upgrade Measure and made the
heating Generator read the dwelling as off-gas (offering HHRSH storage).

Extend the ADR-0035 drag-along to gas boilers (Table 4b 102/104/120): the
overlay now sets the whole coherent companion set — mains_gas, gas main fuel,
heating category 2, fanned flue, full modern controls (2106), a single-rate
meter, and hot water from the main system with the cylinder set from the boiler
type (combi → none, regular/CPSU → cylinder). The main_fuel overlay also flips
mains_gas=True for a "mains gas" fuel. Non-off-peak archetypes now drag an
explicit Single meter so a system switch never leaves a stale Dual.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:48:33 +00:00
Jun-te Kim
706e0072d0
Merge pull request #1337 from Hestia-Homes/fix/predicted-property-display-unknowns
fix(epc-prediction): populate Heating-Control + Ventilation display for predicted properties
2026-06-26 13:45:22 +01:00
Khalim Conn-Kowlessar
ac94a543b1 Set main_heating on the test_validation partial EPC builder 🟩
The heating-donor display synthesis reads donor.epc.main_heating, which has no
dataclass default — so a partial object.__new__ EpcPropertyData must set it.
test_validation's _comparable builder didn't, failing the two leave-one-out
scorer tests in CI (the full epc_prediction suite wasn't run pre-push).
main_heating_controls / sap_ventilation default to None via class attributes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:35:01 +00:00
Jun-te Kim
015ea0a293
Merge pull request #1338 from Hestia-Homes/fix/solar-pv-dwelling-roof-cap
fix(modelling): bound Solar PV array to the dwelling's own roof (ADR-0038)
2026-06-26 13:32:55 +01:00
Khalim Conn-Kowlessar
0a2ed67e94 Harden Dwelling-Roof Cap on real data: positional segments, ground-floor basis 🟩
Three corrections found by re-running property 742003 end-to-end:
- roofSegmentStats are POSITIONAL — real responses omit the segmentIndex field
  the fixture happened to carry; key the centre/area lookup by array position.
- Base the cap on ground_floor_area (the footprint the roof covers), not the
  greatest per-storey area; roof_area is the fallback.
- Clamp the basis by total_floor_area: predicted EPCs borrow the structural
  template's geometry (742003: a 118.62 m² MAIN ground floor) decoupled from
  the predicted 55 m² (ADR-0029), so without the clamp the cap reads the
  template's larger footprint.

Result: 742003 plan A/92.4 (16 kWp) -> C/74.4 (6.4 kWp). 29 solar tests +
orchestration threading + products green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:24:52 +00:00
Khalim Conn-Kowlessar
904c205e3a Dwelling-Roof Cap bounds the PV array to the dwelling's own roof 🟥
select_conservative_configs must accept the dwelling's roof area and cap panels
to its usable roof (ADR-0038) — bounding a 55m² dwelling to ~16 panels under
Google footprint conflation, while staying a no-op on correctly-matched homes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:15:28 +00:00
Khalim Conn-Kowlessar
cf2780ed77 SolarPotential carries panel dims + per-segment centre/area 🟥
The Dwelling-Roof Cap (ADR-0038) sizes by usable roof area and ranks segments
by distance from the dwelling, so the projection must carry each panel's
footprint and each segment's centre + area (from roofSegmentStats).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 12:12:12 +00:00
Khalim Conn-Kowlessar
80c5ad0c6c Predict ventilation kind from the cohort mode 🟥
Prediction never synthesises ventilation — it keeps the size-template's
sap_ventilation, so a predicted dwelling in an MEV/MVHR neighbourhood is scored
+ displayed as natural (predicted property 721167 follow-up). Mode the
mechanical_ventilation_kind across the cohort like glazing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:49:37 +00:00
Khalim Conn-Kowlessar
5cf5b67420 Carry donor's display heating + control into predicted EPC 🟥
_apply_heating_donor copies the donor's calc sap_heating but leaves the
display rows (main_heating, main_heating_controls) on the structural template
— incoherent, and 'Heating Control: Unknown' when the template lodged no
control (predicted property 721167, ADR-0029 follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 10:37:36 +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
100a580119 Add tests for repredict_epc flag routing via stored predicted EPC 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 10:15:40 +00:00
Daniel Roth
a940c94b33 Handler pre-fetches stored EPCs and routes per-property via refetch_epc flag 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 10:13:51 +00:00