Commit graph

512 commits

Author SHA1 Message Date
Khalim Conn-Kowlessar
a63276387e Construct sap_ventilation in from_rdsap_schema_19_0 / 21_0_0 🟩
Both passed no sap_ventilation= → EpcPropertyData default None, dropping the
whole §2 block so MEV/MVHR certs scored as natural. Mirror 21.0.1's block for
the only fields each schema lodges: mechanical_ventilation_kind (§2 MV-kind
dispatch) + sheltered_sides (§S5, from built_form). Neither schema lodges the
fan/flue/vent counts (RdSAP Table-5 age defaults), so those stay unset.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 09:55:08 +00:00
Khalim Conn-Kowlessar
34d97a75f4 Construct sap_ventilation in from_rdsap_schema_19_0 / 21_0_0 🟥
19.0 + 21.0.0 pass no sap_ventilation= at all → EpcPropertyData default None,
dropping the entire §2 block (sheltered_sides + mechanical_ventilation_kind).
Extend the MVHR mapper test to both and add a sheltered_sides regression,
mirroring 21.0.1 (remaining ADR-0037 ventilation follow-up).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 09:53:19 +00:00
Khalim Conn-Kowlessar
e770c876ea Map mechanical_ventilation_kind in the 3 bare-SapVentilation RdSAP mappers 🟩
17.1/18.0/20.0.0 built SapVentilation(sheltered_sides=…) and dropped the cert's
mechanical_ventilation, mis-scoring MEV/MVHR dwellings as natural. Mirror 21.0.1's
_api_mechanical_ventilation_kind. Natural certs (code 0/5 → None) unchanged
(corpus 73.3%/0.774, mapper corpus green, 726605 SAP 68.058 unchanged).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:44:37 +00:00
Khalim Conn-Kowlessar
debbbb84f2 Map mechanical_ventilation_kind in the 3 bare-SapVentilation RdSAP mappers 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-26 08:38:13 +00:00
Khalim Conn-Kowlessar
590a456065 Map main_heating_controls in the older RdSAP mappers for the FE panel 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:43:17 +00:00
Khalim Conn-Kowlessar
a975d870c9 Map main_heating_controls in the older RdSAP mappers for the FE panel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:41:41 +00:00
Khalim Conn-Kowlessar
5deea0a27c Map main_heating_controls on full-SAP certs for the FE panel 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:38:50 +00:00
Khalim Conn-Kowlessar
0440de4965 Map main_heating_controls on full-SAP certs for the FE panel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 21:38:06 +00:00
Khalim Conn-Kowlessar
95701d03e4 Map display EnergyElements on full-SAP certs for the FE panel 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:55:51 +00:00
Khalim Conn-Kowlessar
4c65640e4e Map display EnergyElements on full-SAP certs for the FE panel 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:54:46 +00:00
Khalim Conn-Kowlessar
304e8afb00 Map assessment_type on full-SAP certs 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:53:22 +00:00
Khalim Conn-Kowlessar
33f9988ac5 Map assessment_type on full-SAP certs 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:52:07 +00:00
Khalim Conn-Kowlessar
5149400f96 Map secondary_heating on full-SAP certs for the calculator 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:40:59 +00:00
Khalim Conn-Kowlessar
7b06d9dbab Map secondary_heating on full-SAP certs for the calculator 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:40:30 +00:00
Khalim Conn-Kowlessar
bc394ce5f5 Map built_form on full-SAP certs 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:38:50 +00:00
Khalim Conn-Kowlessar
d2ede36b41 Map built_form on full-SAP certs 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:38:16 +00:00
Khalim Conn-Kowlessar
5c0460cee2 Map property_type on full-SAP certs for correct heat-transmission 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:37:34 +00:00
Khalim Conn-Kowlessar
951bee3115 Map property_type on full-SAP certs for correct heat-transmission 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:36:38 +00:00
Khalim Conn-Kowlessar
cff5b061a4 Map sap_version on full-SAP certs so pre-SAP10 rebaseline fires 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:36:04 +00:00
Khalim Conn-Kowlessar
14c777f37b Map sap_version on full-SAP certs so pre-SAP10 rebaseline fires 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 20:34:35 +00:00
Daniel Roth
c89ab7692d
Merge pull request #1329 from Hestia-Homes/feature/modelling-e2e-bugs
Fix: synthesise SapFloorDimension for SAP-16.0 flats with missing floor dimensions to unblock roof recommendations
2026-06-25 16:12:46 +01:00
Daniel Roth
5a4285e1b7 Include address and postcode in floor-dims synthesis ValueError for triage
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 15:07:07 +00:00
Daniel Roth
8024065d04 Raise ValueError when floor dims absent and synthesis guards cannot fire 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 15:03:03 +00:00
Daniel Roth
e62e5fbfe4 Add comment explaining floor-dim synthesis guard and bungalow coverage gap
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 14:24:59 +00:00
Daniel Roth
76d07dba39 Pin synthesised SapFloorDimension total area and heat-loss perimeter as regression tests 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 14:18:27 +00:00
Daniel Roth
8a909dc15b Mapper synthesises SapFloorDimension for SAP-16.0 flats with empty floor dims 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 14:16:36 +00:00
Daniel Roth
c1e754057b Mapper synthesises SapFloorDimension for SAP-16.0 flats with empty floor dims 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-25 14:14:03 +00:00
Khalim Conn-Kowlessar
48760971a7 Coerce banded flat_location string to its floor integer 🟩
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:01:44 +00:00
Khalim Conn-Kowlessar
862a7ccc61 Coerce banded flat_location string to its floor integer 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-25 12:00:00 +00:00
Daniel Roth
a6752c2654
Merge pull request #1306 from Hestia-Homes/fix/full-sap-16x-cert-mapping
Route full-SAP certs lodged under SAP-Schema-16.x to the full-SAP mapper
2026-06-24 17:22:03 +01:00
Daniel Roth
1a37caa44d
Merge pull request #1308 from Hestia-Homes/fix/conservatory-age-band-sibling-mappers
Map non-separated conservatory on the 17.0/17.1/18.0/20.0.0 gov paths 🟩
2026-06-24 17:19:23 +01:00
Daniel Roth
8244d3f116
Merge pull request #1307 from Hestia-Homes/feature/unmapped-ventilation-type-10
Map SAP ventilation_type codes 7/8/9/10 correctly in full-SAP schema path 🟩
2026-06-24 17:05:08 +01:00
Daniel Roth
3e8e29b6d2 Map SAP ventilation_type codes 7/8/9/10 correctly in full-SAP schema path 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 15:58:46 +00:00
Khalim Conn-Kowlessar
700f44cbbc Map non-separated conservatory on the 17.0/17.1/18.0/20.0.0 gov paths 🟩
Ports the §6.1 conservatory split (declare the four glazed fields; exclude the
glazed BP from the fabric loop; carry it as sap_conservatory) to the remaining
gov mappers that lacked it. Fixes the modelling_e2e construction_age_band
NOT-NULL failures: 5 type-4 conservatory certs on RdSAP-Schema-20.0.0 (e.g.
property 725213) mapped the conservatory to a null-age fabric part that crashed
on persist. 17.0/17.1/18.0 ported preventively (no-op for non-conservatory
certs). 21.0.0 deferred — it never adopted the ADR-0027 all-Optional
SapBuildingPart, so a sparse conservatory part needs that broader change first.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:58:14 +00:00
Jun-te Kim
e312aae95d Generalise to a 'broken schema type' gate keyed on assessment_type
Per review (Khalim): lift the full-SAP detection out of the SAP-Schema-16.x
branch into a single top-level gate in from_api_response, and key it on the
gov-API's own assessment_type declaration rather than the structural
sap_opening_types proxy.

- _is_full_sap_assessment(data): assessment_type == "SAP" — the authoritative
  SAP-vs-RdSAP classification. Verified to separate the entire fixture corpus:
  every full-SAP schema (SAP-Schema-17.x/18.x + the broken LIG 16.x) is "SAP";
  every reduced cert (RdSAP-Schema-* and reduced SAP-Schema-16.x, incl.
  sap_16_0.json) is "RdSAP". data_type / sap_opening_types agree but are derived
  shape artifacts; assessment_type is the meaning.
- A cert that is full-SAP by assessment_type but whose schema_type LABEL is not a
  recognised full-SAP schema is a *broken schema type* (label disagrees with the
  assessment). _record_broken_schema_type logs it — visible, not silently
  rerouted — so unreliable labels surface and coverage grows as new mislabels
  appear. Generalises beyond 16.x to any future mislabel.
- _from_full_sap maps it via the full-SAP 17.1 mapper (real measured openings,
  no defaulting; only `tenure` defaulted). Correctly-labelled full-SAP certs keep
  their dedicated branches (one-mapper-per-schema convention); reduced certs are
  unchanged.

Tests: broken cert routed AND recorded; correctly-labelled full-SAP not recorded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:39:16 +00:00
KhalimCK
422c943748
Merge pull request #1305 from Hestia-Homes/feature/e2e-runs
Feature/e2e runs
2026-06-24 16:25:22 +01:00
Jun-te Kim
5e0963593a Route full-SAP certs lodged under SAP-Schema-16.x to the full-SAP mapper
A full-SAP cert (assessment_type=SAP, the as-designed LIG-* new-builds) lodged
under a SAP-Schema-16.x version failed to map with:

  ValueError: RdSapSchema17_1: missing required field 'door_count'

— crashing the property's modelling_e2e subtask. 89 distinct properties in the
2026-06-24 run hit this; ~22 of every 30 sampled are this full-SAP shape.

Root cause: from_api_response dispatches on the schema_type STRING only, and the
SAP-Schema-16.x branch assumed a single shape — "reduced-field (RdSAP-shaped)" —
sending every 16.x cert through _normalize_sap_schema_16_x -> RdSapSchema17_1.
But the SAP-Schema-16.x name covers two structurally different certs:

  * reduced RdSAP (assessment_type=RdSAP): top-level door_count / glazed_area
    band / construction-code building parts.
  * full SAP    (assessment_type=SAP): measured shape — sap_opening_types +
    structured sap_building_parts carrying measured U-values and door/window
    OPENINGS, with NO top-level door_count (the door is an opening). These omit
    the reduced-only count fields, so the reduced normaliser failed loud on the
    first one it checks (door_count) — and 14 others behind it.

Force-fitting a full-SAP cert to the reduced RdSAP schema was the bug: the data
was never missing, it was being validated against the wrong schema.

Fix: discriminate on shape (_is_full_sap_cert: assessment_type=SAP AND
sap_opening_types present) and route full-SAP 16.x certs to the existing
full-SAP 17.1 mapper, which reads the real measured openings (the lodged
0.9x2.1m door -> door_count 1) — no reduced-field defaulting. The only field the
16.x full-SAP shape omits that SapSchema17_1 needs is `tenure` (register
metadata, no SAP effect), defaulted. Reduced 16.x certs (assessment_type=RdSAP,
no opening types) are untouched — all pinned reduced 16.x fixtures stay on the
RdSAP path.

Regression test pins a real full-SAP-16.0 cert (0293-...-8795, lodged 83) mapping
via the full-SAP path + the reduced 16.2 cert staying on the RdSAP path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 15:16:51 +00:00
Khalim Conn-Kowlessar
56add97bd9 Map non-separated conservatory on the gov-API RdSAP-19.0 path 🟩
Mirror the merged 21.0.1 fix (d501535c): declare the four glazed conservatory
fields on the 19.0 SapBuildingPart so from_dict stops dropping them, exclude the
glazed BP from the fabric loop, and carry it as EpcPropertyData.sap_conservatory
(§6.1). Fixes cert 718138 (conservatory_type=4) mis-scoring as a fabric part and
failing to persist on the NOT-NULL construction_age_band.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 13:56:03 +00:00
Daniel Roth
40a079e464 21.0.1 mapper coalesces omitted led_fixed_lighting_bulbs_count to 0 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:19:10 +00:00
Daniel Roth
e906bbecf8 21.0.1 mapper coalesces omitted led_fixed_lighting_bulbs_count to 0 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:17:19 +00:00
Daniel Roth
71269637ef 21.0.1 mapper coalesces omitted cfl_fixed_lighting_bulbs_count to 0 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:16:29 +00:00
Daniel Roth
d36fa2b5cd 21.0.1 mapper coalesces omitted cfl_fixed_lighting_bulbs_count to 0 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:15:37 +00:00
Daniel Roth
a01a940df2 21.0.1 mapper coalesces omitted open_chimneys_count to 0 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:14:36 +00:00
Daniel Roth
6efbd4649d 21.0.1 mapper coalesces omitted open_chimneys_count to 0 🟥
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-24 13:13:43 +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
Jun-te Kim
e9a8ad9cd9
Merge pull request #1290 from Hestia-Homes/fix/building-part-int-identifier
Tolerate non-string building-part identifier (fix TypeError, cohort cert)
2026-06-24 11:59:31 +01:00
Jun-te Kim
170fd1bf71
Merge pull request #1291 from Hestia-Homes/fix/full-sap-has-hot-water-cylinder
Fall back to nested has_hot_water_cylinder for full-SAP certs (cohort cert)
2026-06-24 11:59:03 +01:00
Jun-te Kim
e4a79648ab
Merge pull request #1292 from Hestia-Homes/fix/sap-opening-type-6
Map full-SAP opening-type 6 (rooflight) as a roof window (5 cohort certs)
2026-06-24 11:58:53 +01:00
Jun-te Kim
789103af27 Map full-SAP opening-type 6 (rooflight) as a roof window
5 modelling_e2e cohort certs (full-SAP 19.1.0) were skipped with
"unmapped API sap_opening_type code: 6". Code 6 is "Ext Rooflight"; SAP 10.2
treats roof windows and rooflights as the same inclined-glazing family.

Fix: add 6 to the known opening-type taxonomy and route it onto the roof-window
path (`sap_roof_windows`) alongside code 5, via a `_SAP_ROOF_WINDOW_TYPES`
{5, 6} set. Genuinely-unknown codes (e.g. 99) still raise.

Cert 9878-3908-6309-6714-8200 now maps + calculates (sap 81). Regression test:
a type-6 opening maps onto sap_roof_windows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:47:33 +00:00
Jun-te Kim
18063a2d7f Fall back to nested has_hot_water_cylinder for full-SAP certs
A SAP-Schema-17.0 full-SAP cohort cert (8265-7433-3220-9736-7902) omits the
top-level `has_hot_water_cylinder` and lodges it only under `sap_heating`. The
required top-level field on SapSchema17_1 made `from_dict` raise and skip the
cert.

Fix: make the top-level field Optional, and have the full-SAP mapper
(`from_sap_schema_17_1`, also used by 17.0/18.0.0 via delegation) fall back to
`sap_heating.has_hot_water_cylinder`. RdSAP mappers are unchanged (they keep the
top-level required field; their SapHeating has no such attribute).

Cert now maps + calculates (sap 76). Regression tests for the nested true/false
fallback.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 10:43:18 +00:00