Commit graph

7222 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
1552e24fa5 Recognise an air source heat pump via the default ASHP code 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:30:00 +00:00
Khalim Conn-Kowlessar
646bff38a6 Recognise an air source heat pump via the default ASHP code 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:28:48 +00:00
Khalim Conn-Kowlessar
dbcd2e3840 Run the fuel-mismatch check on every Property's resolved overrides 🟩
Wire flag_fuel_mismatch into the two override-resolution paths (the property
repository and the modelling-e2e handler), keeping overlays_from a pure mapping.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:21:32 +00:00
Khalim Conn-Kowlessar
13a6a213fb Treat a same-family fuel refinement as consistent, not a mismatch 🟩
Compare fuel families (not exact codes), so a solid-fuel room heater refined to
smokeless/dual/biomass is consistent; only a different family (gas/electric on a
solid heater) is logged.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:18:51 +00:00
Khalim Conn-Kowlessar
27f6b8e9ae Treat a same-family fuel refinement as consistent, not a mismatch 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:17:04 +00:00
Khalim Conn-Kowlessar
79fe54a822 Log a landlord fuel that contradicts the heating archetype's natural fuel 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:16:14 +00:00
Khalim Conn-Kowlessar
648013e05c Log a landlord fuel that contradicts the heating archetype's natural fuel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:15:16 +00:00
Khalim Conn-Kowlessar
6276730cfe A main_fuel override beats a heating archetype's natural-fuel default 🟩
overlays_from now applies main_fuel after main_heating_system (stable sort), so
an explicit landlord fuel wins the natural-fuel default the heating archetype
drags, regardless of override row order. apply_simulations is last-wins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:06:56 +00:00
Khalim Conn-Kowlessar
260e3cbd32 A main_fuel override beats a heating archetype's natural-fuel default 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 17:04:44 +00:00
Khalim Conn-Kowlessar
56aaace5b1 Default a solid-fuel room heater's natural fuel to house coal 🟩
Solid fuel is ambiguous across coal/wood/smokeless/pellets, so the overlay
defaults to house coal (33, the most common) when no main_fuel override is
given; a specific solid-fuel override still wins by last-wins composition.
Updates the ADR-0041 natural-fuel amendment accordingly (every archetype drags
a natural fuel; solid defaults to coal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:55:57 +00:00
Khalim Conn-Kowlessar
390df5a6bd Default a solid-fuel room heater's natural fuel to house coal 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:54:07 +00:00
Khalim Conn-Kowlessar
d5927c68a9 docs: ADR-0041 amendment — natural-fuel coherence
Record the natural-fuel drag-along rule the overlay now implements: drag a fuel
only where the archetype is unambiguous (electric/gas), leave ambiguous
solid/oil room heaters to the main_fuel override, let a present main_fuel
override win by last-wins composition, and LOG (not raise) a landlord fuel that
contradicts the archetype's natural fuel.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:46:56 +00:00
Khalim Conn-Kowlessar
d8acc9baa5 Drag electricity as an electric room heater's natural fuel 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:46:18 +00:00
Khalim Conn-Kowlessar
5a29238480 Drag electricity as an electric room heater's natural fuel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:45:20 +00:00
Khalim Conn-Kowlessar
0cd30a13e6 Drag a solid-fuel room heater's coherent room-heater companions 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:44:04 +00:00
Khalim Conn-Kowlessar
d5280e9d96 Drag a solid-fuel room heater's coherent room-heater companions 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 16:42:48 +00:00
Khalim Conn-Kowlessar
f097561160 Recognise a solid-fuel room heater as its own heating archetype 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:44:30 +00:00
Khalim Conn-Kowlessar
d51154fe73 Recognise a solid-fuel room heater as its own heating archetype 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:43:24 +00:00
Khalim Conn-Kowlessar
72e1e67c6d docs: ADR-0041 — landlord-heating classification targets a complete taxonomy
grill-with-docs output for PRD #1361 Class A. The band-G baselines are not a
fabric/rebaseline bug (walls are correct — landlord asserted as-built); they are
a target-vocabulary gap in the landlord-description heating classifier. The LLM
maps unbounded free-text onto a closed internal taxonomy, but that taxonomy had
9 archetypes vs ~13 RdSAP families, so it overflowed into "Gas CPSU"/storage
(the "convector" collision sent direct-acting room heaters to off-peak storage
403 → SAP ~10).

- ADR-0041: fix the taxonomy not the mapper; unmapped input -> None (keep lodged
  EPC, surface to user), never a forced archetype; heat pumps modellable via a
  default Table 4a code (no PCDB id); community heating via codes 301/302/304
  with a documented DLF-1.50 / boiler-source default.
- CONTEXT.md: sharpen Landlord-Description Classification and the four distinct
  vocabularies (landlord / recognised-internal / lodged / SAP code).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:33:54 +00:00
KhalimCK
ee9a1c4d90
Merge pull request #1364 from Hestia-Homes/audit/schema-mapping-gaps
Audit other schema mappers for the meter/PV drop class — fix full-SAP 18-hour tariff
2026-06-30 11:08:23 +01:00
Daniel Roth
d623a29c2d Merge branch 'main' into audit/schema-mapping-gaps 2026-06-30 10:00:33 +00:00
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
Daniel Roth
398016505d
Merge pull request #1362 from Hestia-Homes/audit/portfolio-796-scenario-1268
docs(audit): record stale-default-plan expectation + default-plan-only rule
2026-06-30 08:36:29 +01:00
Khalim Conn-Kowlessar
450ecfb9b4 Lock full-SAP 16.x tariff translation via the assessment_type gate 🟩
Confirming regression test for the prime-lead suspicion (SAP-16.x meter
over-rating). A full-SAP-shaped 16.x cert lodges the SAP energy_tariff code
space; the assessment_type=SAP gate routes it to the full-SAP mapper, which
translates the code (1=standard → STANDARD) rather than raw-passing it to the
RdSAP normaliser (where 1="dual" → SEVEN_HOUR, the over-rating bug). No fix
needed — the gate already prevents the drop; this pins that behaviour.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:58:35 +00:00
Khalim Conn-Kowlessar
7866b4a34c Translate full-SAP 18-hour off-peak tariff (code 5) to EIGHTEEN_HOUR 🟩
Add code 5 → "off-peak 18 hour" to _SAP_TARIFF_TO_RDSAP_METER_TYPE so the
full-SAP meter translation covers the whole energy_tariff code space, not
just 1-4. Table 12a resolves the word alias to Tariff.EIGHTEEN_HOUR.

Real SAP-19.1.0/19.2.0 sample certs lodge tariff 5 and now resolve to the
18-hour off-peak split instead of defaulting to STANDARD (under/over-rated).
The same fix covers 17.0/17.1/18.0.0/19.0.0 — all route through the full-SAP
mapper via the assessment_type=SAP gate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:55:40 +00:00
Khalim Conn-Kowlessar
c6c07c2c51 Full-SAP 18-hour off-peak tariff (code 5) must resolve to EIGHTEEN_HOUR 🟥
The full-SAP energy_tariff code space includes 5=off-peak-18-hour, but
_sap_17_1_meter_type only maps 1-4, dropping code 5 to "" → STANDARD.
Real SAP-19.1.0/19.2.0 certs lodge tariff 5, so the 18-hour off-peak
split is silently lost.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:50:34 +00:00
Khalim Conn-Kowlessar
0b8765481d Engine now matches lodged 82 on a PV cert (was under-rating to 80) 🟩
Crediting the full-SAP lodged PV closes the 2-point under-rating on uprn
10023444324 — the engine now reproduces the accredited lodged value exactly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 22:01:33 +00:00
Khalim Conn-Kowlessar
ea7f4f4329 Carry full-SAP lodged PV arrays through to the domain 🟩
Full-SAP certs lodge measured PV under sap_energy_source.pv_arrays, but the
SAP-Schema-17.1 SapEnergySource modelled only wind, so from_dict dropped it at
parse and the mapper hardcoded no PV. A new SapPvArray schema field + the
_sap_17_1_pv_arrays mapper helper carry it to the domain photovoltaic_arrays the
Appendix-M generation credit reads — without it an all-electric dwelling the
array lifts to A/B is mis-modelled down a band or more.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:59:21 +00:00
Khalim Conn-Kowlessar
4393812638 Carry full-SAP lodged PV arrays through to the domain 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 21:51:09 +00:00
Khalim Conn-Kowlessar
e02e6a76e1 Preserve an existing more-off-peak cert meter under a heating overlay 🟩
A landlord heating override DESCRIBES the dwelling, so its assumed off-peak meter
(Dual/E7) is a coherent default — it must not downgrade a cert that already
lodges a more-off-peak meter (e.g. property 709874's 24-hour all-low tariff). The
overlay opts in via keep_existing_off_peak_meter; _fold_heating then keeps the
cert's meter when both it and the desired meter are off-peak. Heating MEASURES
build HeatingOverlay directly and leave the flag False, so they still re-meter
for real (Elmhurst re-lodges 18-hour -> Dual on a storage install) — the cascade
pins stay green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 20:32:31 +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
6279924773 Stop a System-built landlord override being mis-read as a basement 🟩
System-built is RdSAP code 6, colliding with the gov-EPC code-6 basement
sentinel that main_wall_is_basement falls back to. The wall overlay now pins
wall_is_basement=False for system-built, mirroring the gov-API mapper's
_clear_basement_flag_when_system_built, so the override no longer adds a phantom
basement (which inflated both wall and ground-floor heat loss).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 19:37:11 +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
6ec0989283 Translate full-SAP electricity tariff into the RdSAP meter type 🟩
Full-SAP energy_tariff (1=standard/2=7hr/3=10hr/4=24hr) and RdSAP meter_type
(1=dual/2=single/3=unknown/4=24hr) are different code spaces; the mapper passed
the code through untranslated, reading standard-tariff full-SAP certs as Economy 7
(over-rated) and Economy-7 certs as single (under-rated). Map onto the RdSAP word
aliases so the resolved Table 12a tariff is correct; absent/ND -> unknown.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 18:54:51 +00:00
Khalim Conn-Kowlessar
a764b5fa9c Translate full-SAP electricity tariff into the RdSAP meter type 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 18:45:27 +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
54acc0388b docs(audit): record stale-default-plan expectation + default-plan-only rule 🟪
Portfolio-796/scenario-1268 audit found the bulk of MEDIUM/HIGH anomalies
(already-meets-goal-with-works, zero-works-post-differs, plan-score-below-
baseline, and the non-fuel-switch slice of negative-bill-savings) trace to one
root cause: the persisted default plan is stale relative to the live model, so
it resolves on re-model rather than a code change. Confirmed via
run_modelling_e2e on three samples (stored vs live plans differ wholesale).

No new check added — the staleness is already surfaced by the existing checks
and addressed by the override-aware-rebaseline / persistence-fidelity work, so
a new check would only re-flag known divergence. Instead record the expectation
and the "audit the default plan only" rule in the skill Notes so the next
reviewer starts ahead. References kept to durable docs/adr (no PR numbers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 16:08:17 +00:00
Khalim Conn-Kowlessar
4b2f406b6c 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:01:07 +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
ada2bc078e Map landlord electric room heaters to the direct-acting room-heater SAP code 🟩
'Electric room heaters' archetype -> SAP Table 4a code 691 (panel/convector/
radiant), on a single-rate meter (691 is not off-peak-implying, unlike storage).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:59:25 +00: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
Daniel Roth
6c42065304
Merge pull request #1358 from Hestia-Homes/feature/batch-save-and-delete-epc
Batch saving and deleting of epc property data, bulk saving of plans
2026-06-29 16:46:19 +01: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
dbaf3c49e2 fix(hp): floor heat-pump water-heating efficiency at 100% (App N3.7) 🟩
_heat_pump_apm_efficiencies applied the Table N8 in-use factor to the PCDB
water-heating efficiency but omitted the spec's "subject to a minimum
efficiency of 100%" clause (SAP 10.2 Appendix N3.7, PDF p.109). An oversized
heat pump whose PSR-extended water,3 x the 0.60 in-use factor fell below
100% therefore billed water heating at that sub-100% efficiency, over-
counting hot-water fuel.

Apply max(in_use x eta_water, 100%). Accredited Elmhurst worksheet for cert
100110101713 (golden fixture case 56, PCDB 100061): water (216) = 100.0000,
which we now match (was 77.13%). Combined with the space-heating PSR-
extension fix the cert lands 72.51 vs lodged 73 (|err| 18.32 -> 0.49).

Data-driven: only the single oversized-PSR cert moves (in-range heat pumps
keep their > 100% water COP, e.g. case 54 112.5%, case 55 179.6%). Corpus
(RdSAP-21.0.1 n=1000) MAE 0.726 -> 0.721, within-0.5 74.1% -> 74.2%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 15:38:31 +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
235c2ca466 Merge remote-tracking branch 'origin/main' into fix/heat-pump-flow-temp-efficiency 2026-06-29 15:17:10 +00:00