diff --git a/docs/adr/0041-landlord-heating-classification-targets-a-complete-modellable-taxonomy.md b/docs/adr/0041-landlord-heating-classification-targets-a-complete-modellable-taxonomy.md index 3efcc1c9f..47614fe56 100644 --- a/docs/adr/0041-landlord-heating-classification-targets-a-complete-modellable-taxonomy.md +++ b/docs/adr/0041-landlord-heating-classification-targets-a-complete-modellable-taxonomy.md @@ -108,13 +108,15 @@ A room-heater / direct-acting archetype names a *system*, not its fuel — and f arrives as its own composable `main_fuel` override. Two rules keep the system self-coherent without coupling the two overlays: -- **The heating overlay drags a natural fuel only where the archetype is - unambiguous** — electric room heaters / direct-acting / storage are - unambiguously electricity (RdSAP `main_fuel` code 29), a gas boiler is mains - gas (26). A **solid / oil room heater is fuel-ambiguous** (coal vs wood vs - smokeless), so it drags **no** natural fuel and relies on the `main_fuel` - override; dragging a guessed coal-vs-wood code would be *more* wrong (very - different carbon). +- **Every archetype drags a natural fuel so the system self-coheres without a + `main_fuel` override.** Where the fuel is unambiguous it is exact — electric + room heaters / direct-acting / storage → electricity (RdSAP `main_fuel` 29), a + gas boiler → mains gas (26), an oil room heater → oil (28). **Solid fuel is + ambiguous** (coal / anthracite / smokeless / dual fuel / wood logs / pellets), + so it **defaults to house coal (33)** — the most common solid fuel — which a + specific `main_fuel` override then refines. (The `main_fuel` override's own + vocabulary must grow to carry the full solid-fuel list — a parallel taxonomy + gap, same shape as this one.) - **A present `main_fuel` override wins** by the applicator's last-wins composition (`apply_simulations` setattrs non-`None` fields in order), so the `main_fuel` overlay is applied **after** the heating overlay. The agreeing diff --git a/domain/epc/property_overlays/main_heating_system_overlay.py b/domain/epc/property_overlays/main_heating_system_overlay.py index bc00cf350..b08b230cf 100644 --- a/domain/epc/property_overlays/main_heating_system_overlay.py +++ b/domain/epc/property_overlays/main_heating_system_overlay.py @@ -84,9 +84,12 @@ _SOLID_FUEL_ROOM_HEATER_CODES = frozenset(range(631, 637)) # that lodged a different fuel. A later `main_fuel` override still wins (last-wins # composition); a contradicting landlord fuel is logged, not silently overridden. # Electric room heaters (Table 4a 691-701) are unambiguously electricity (RdSAP -# main_fuel code 29). Solid/oil room heaters are fuel-ambiguous (coal vs wood vs -# smokeless), so they drag no natural fuel and rely on the `main_fuel` override. +# main_fuel code 29). Solid fuel is ambiguous (coal / anthracite / smokeless / +# dual fuel / wood logs / pellets), so it defaults to house coal (33) — the most +# common solid fuel — when the landlord gives no `main_fuel` override; a specific +# solid-fuel override still wins by last-wins composition. _ELECTRICITY_FUEL = 29 +_HOUSE_COAL_FUEL = 33 _ELECTRIC_ROOM_HEATER_CODES = frozenset(range(691, 702)) # SAP Table 4c full boiler-control code: programmer + room thermostat + TRVs. The @@ -171,6 +174,8 @@ def _natural_fuel_for(code: int) -> Optional[int]: present `main_fuel` override wins by last-wins composition.""" if code in _ELECTRIC_ROOM_HEATER_CODES: return _ELECTRICITY_FUEL + if code in _SOLID_FUEL_ROOM_HEATER_CODES: + return _HOUSE_COAL_FUEL return None