From 23c7b1dcdf642b2b2b2c4207c5083cc626d9d88e Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Thu, 23 Jul 2026 15:19:28 +0000 Subject: [PATCH] fix(filters): bucket the oil boiler heating archetypes as Oil, not Unknown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #455 added three main_heating_system values — "Oil boiler, regular", "Oil boiler, combi" and "Solid fuel boiler" — without a matching needle. The two oil ones fell through every bucket to Unknown, which the vocabulary-coverage test caught: an overridden component that displays but cannot be filtered (ADR-0012). The gap is specific to these archetypes. Every other oil value carries its fuel *after* a comma ("Boiler and radiators, oil"), which the ", oil" needle matches; these lead with it. Bare "oil" is unusable as a needle because it is a substring of "b(oil)er", so the fix is the narrower "oil boiler" — which cannot collide with "solid fuel boiler", and Solid Fuel is checked first regardless. "Solid fuel boiler" already bucketed correctly. One edit fixes both halves: the portfolio query's SQL bucketing reads the same DESCRIPTOR_FILTER_CONFIG rather than restating the needles, so the classifier and the SQL cannot drift here. Also asserts these three by *bucket* rather than relying on the coverage test's "not Unknown" — the failure that matters is a wrong bucket, and a reordered needle list would silently make "Oil boiler, combi" a Gas Boiler while the coverage test kept passing. --- src/app/utils/propertyFilters.ts | 6 ++++-- src/lib/services/descriptorResolution.test.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/app/utils/propertyFilters.ts b/src/app/utils/propertyFilters.ts index 56b178a6..27b4f09a 100644 --- a/src/app/utils/propertyFilters.ts +++ b/src/app/utils/propertyFilters.ts @@ -269,8 +269,10 @@ export const HEATING_SYSTEM_OPTIONS: DescriptorBucket[] = [ { label: "Community", needles: ["community"] }, { label: "Solid Fuel", needles: ["coal", "anthracite", "smokeless", "wood", "dual fuel", "biomass", "solid fuel"] }, // NB: bare "oil" is a substring of "b(oil)er" — match the fuel token only (", oil" - // as in "Boiler and radiators, oil") and the leading override "Oil room heater". - { label: "Oil", needles: [", oil", "oil room heater"] }, + // as in "Boiler and radiators, oil") and the leading override vocabulary + // ("Oil room heater …", "Oil boiler, regular/combi"). "oil boiler" cannot + // collide with "solid fuel boiler", and Solid Fuel is checked first regardless. + { label: "Oil", needles: [", oil", "oil room heater", "oil boiler"] }, { label: "LPG", needles: ["lpg"] }, { label: "Gas Room Heater", needles: ["gas room heater", "room heaters, mains gas", "room heaters, gas"] }, { label: "Gas Boiler", needles: ["mains gas", "gas boiler", "gas cpsu"] }, diff --git a/src/lib/services/descriptorResolution.test.ts b/src/lib/services/descriptorResolution.test.ts index 1c487586..844b3920 100644 --- a/src/lib/services/descriptorResolution.test.ts +++ b/src/lib/services/descriptorResolution.test.ts @@ -507,6 +507,20 @@ describe("classifyDescriptor — wall / roof / heating buckets", () => { expect(heat("Boiler and radiators, dual fuel (mineral and wood)")).toBe("Solid Fuel"); expect(heat("Boiler and radiators, lpg")).toBe("LPG"); }); + + // The non-gas wet-boiler archetypes: their fuel leads the string rather than + // following a comma, so they are the case the ", oil" needle cannot catch. + // Asserted by bucket rather than just "not Unknown", because the failure mode + // that matters is a *wrong* bucket — reorder the needles and "Oil boiler, + // combi" silently becomes a Gas Boiler, which the coverage test would pass. + it("buckets the non-gas wet-boiler override archetypes by their fuel", () => { + expect(heat("Oil boiler, regular")).toBe("Oil"); + expect(heat("Oil boiler, combi")).toBe("Oil"); + expect(heat("Solid fuel boiler")).toBe("Solid Fuel"); + // Guard the collision the "oil boiler" needle could have caused: Solid Fuel + // is checked first, and a gas boiler still has no "oil" fuel token. + expect(heat("Gas boiler, combi")).toBe("Gas Boiler"); + }); }); /** Legacy-property helper: only year_built is set, cutoff is false. */