Model/domain/modelling/generators
Khalim Conn-Kowlessar 63dd69ff8b feat(modelling): gas combi boiler upgrade + controls-when-inadequate
Extend the gas-boiler-upgrade Option to combi (no-cylinder) dwellings and add
the controls upgrade shared by both boiler shapes. A dwelling has a cylinder or
it does not, so the one `gas_boiler_upgrade` Option is shaped per dwelling:

- no cylinder -> a gas condensing combi (Table 4b code 104), no cylinder fields
  touched;
- a cylinder  -> a regular boiler (code 102) heating it, with the conditional
  cylinder jacket/thermostat (slice 1).

Controls: bring an inadequate boiler control up to full programmer + room
thermostat + TRVs (SAP 10.2 Table 4e Group 1 code 2106). "Inadequate" = the
Group-1 codes with NO room thermostat (2101, 2102, 2107, 2108, 2109, 2111) —
these lack boiler interlock (Table 4c(2) / footnote c) p.171), so adding a room
thermostat genuinely improves SAP. Room-thermostatted (2103/2104/2105/2106/2113)
or better zone controls (2110/2112) are left unchanged — never downgraded, so
no phantom uplift. The with-cylinder cert (control 2106) is therefore untouched
and its pin still holds at delta 0.

Validated by the combi before/after re-lodgement (cert 001431, gas boiler
upgrade - no cylinder): control 2111 "TRVs and bypass" -> 2106, fan flue
False->True, SAP code 112 -> 104. Cascade-pinned delta 0 (SAP/CO2/PE). Removed
the slice-1 placeholder test asserting no boiler Option fires without a cylinder
(the combi Option now correctly fires there).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:28:00 +00:00
..
__init__.py refactor(modelling): group domain/modelling into generators/scoring/optimisation 2026-06-03 13:48:36 +00:00
floor_recommendation.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
glazing_recommendation.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
heating_recommendation.py feat(modelling): gas combi boiler upgrade + controls-when-inadequate 2026-06-09 16:28:00 +00:00
lighting_recommendation.py feat(modelling): MeasureType StrEnum as the canonical measure vocabulary 2026-06-08 19:54:04 +00:00
roof_recommendation.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
solar_recommendation.py feat(modelling): MeasureType StrEnum as the canonical measure vocabulary 2026-06-08 19:54:04 +00:00
solid_wall_recommendation.py refactor(modelling): type measure_type fields as MeasureType 2026-06-08 20:13:31 +00:00
ventilation_recommendation.py feat(modelling): MeasureType StrEnum as the canonical measure vocabulary 2026-06-08 19:54:04 +00:00
wall_recommendation.py feat(modelling): MeasureType StrEnum as the canonical measure vocabulary 2026-06-08 19:54:04 +00:00