From f50ee5f957d2294e3489dbdbbff4d0119a3521c4 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 1 Jul 2026 16:51:22 +0000 Subject: [PATCH] =?UTF-8?q?Reclassify=20electric-underfloor=20overrides=20?= =?UTF-8?q?via=20the=20generalized=20main-heating=20reclassify=20?= =?UTF-8?q?=F0=9F=9F=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/reclassify_main_heating.py | 4 +- tests/scripts/test_reclassify_main_heating.py | 40 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/scripts/reclassify_main_heating.py b/scripts/reclassify_main_heating.py index 0d070445e..b21f9b78a 100644 --- a/scripts/reclassify_main_heating.py +++ b/scripts/reclassify_main_heating.py @@ -1,11 +1,13 @@ """One-time re-classification of main-heating overrides funnelled into a garbage drawer for want of a correct archetype (#1376). -Covers both dumping grounds the ``main_heating_guard`` now rescues: +Covers the dumping grounds the ``main_heating_guard`` now rescues: - **HHRSH** (ADR-0044): "High heat retention storage heaters" → "Electric storage heaters, old" (SAP 401), the worst old type — 111 rows. - **Gas CPSU** (ADR-0045): solid-fuel room heaters (open fire / + back boiler / closed + boiler) and electric "NA"-type boilers → "Gas CPSU" (120, mains gas). +- **Electric underfloor** (ADR-0046): concrete slab (421) / integrated (422) / + screed (424) dumped into Direct-acting (191) / old storage (401). The live classifier now applies ``main_heating_guard`` deterministically (so new intakes are correct); this fixes the rows written before it. The **same guard** diff --git a/tests/scripts/test_reclassify_main_heating.py b/tests/scripts/test_reclassify_main_heating.py index 8c172d0c5..7b2450357 100644 --- a/tests/scripts/test_reclassify_main_heating.py +++ b/tests/scripts/test_reclassify_main_heating.py @@ -65,12 +65,50 @@ def test_garbage_drawer_rows_are_remapped_to_faithful_archetypes() -> None: } +def test_electric_underfloor_rows_are_remapped_off_direct_acting_and_old_storage() -> None: + # Underfloor dumped into Direct-acting (191) / old storage (401) → its own codes + # (ADR-0046). Description-determined, so the guard-based reclassify handles it. + stored = [ + ( + "electric underfloor heating: in concrete slab (off-peak only)", + "Direct-acting electric", + ), + ( + "electric underfloor heating: integrated (storage+direct-acting) (off peak)", + "Electric storage heaters, old", + ), + ( + "electric underfloor heating: in screed above insulation (standard or off peak)", + "Direct-acting electric", + ), + ] + + # Act + corrections = main_heating_corrections(stored) + + # Assert + assert corrections == { + "electric underfloor heating: in concrete slab (off-peak only)": ( + "Electric underfloor, in concrete slab (off-peak)" + ), + "electric underfloor heating: integrated (storage+direct-acting) (off peak)": ( + "Electric underfloor, integrated storage and direct-acting" + ), + "electric underfloor heating: in screed above insulation (standard or off peak)": ( + "Electric underfloor, in screed above insulation" + ), + } + + def test_every_guard_target_round_trips_to_a_resolvable_archetype() -> None: # Every archetype the guard emits for the rescued descriptions must decode to a # real SAP heating code — a guard/overlay drift can't silently write an - # unmodellable value (ADR-0044, ADR-0045). + # unmodellable value (ADR-0044, ADR-0045, ADR-0046). descriptions = [ "Electric Storage Systems: High heat retention storage heaters", + "Electric Underfloor Heating: In concrete slab (off-peak only)", + "Electric Underfloor Heating: Integrated (storage+direct-acting) (off peak)", + "Electric Underfloor Heating: In screed above insulation (standard or off peak)", "Solid fuel room heaters: Open fire in grate", "Solid fuel room heaters: Open fire with back boiler (no radiators)", "Solid fuel room heaters: Closed room heater with boiler (no radiators)",