The printed "candidate measures considered" now matches what the
orchestrator actually offered — on 711795 the lodged cavity wall printed
a cavity-fill candidate the plan (timber-frame effective wall) never saw.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Regression guard: category 8 + control 2701 keep the ADR-0048 coherence
invariant satisfied for SAP codes 421/422/424.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WS2 of PRD #1435, diagnosed on property 711795: an electric-underfloor
override inherits the replaced community-heating category (no pathway,
baseline mis-rated 51 vs 67), and wall generators offer £4k insulation
that cannot change an age-band-L wall's derived U (0.280 → 0.280).
Glossary: Wall U-Value Gate.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Walked the water-heating worksheet section: assumed occupancy (42) matched
exactly (2.4234 both sides), but (43) average daily hot water use was
117.41 L/day (Elmhurst) vs 110.73 L/day (ours) — same occupancy, different
shower/bath demand. Root cause: the cert's shower_outlets field is
genuinely unlodged, which the mapper correctly maps to 0 mixer showers
per its documented, already-validated "no entry = no shower" convention.
Elmhurst's build shows a "Non-electric shower" fixture anyway — its UI
silently defaults one when the build script doesn't explicitly configure
"0 showers" to match the cert.
Verified: a single 7 L/min vented mixer reproduces Elmhurst's (42a)
monthly series exactly (4 d.p., all 12 months) and closes hot water to
2616.04 vs Elmhurst's 2616.03. Corpus-wide check across 170 certs sharing
this "bath present, no shower data" pattern shows no systematic bias
(mean dSAP +0.12, median -0.04) — confirms the mapper convention is
correct on average; this is a build-entry artifact on this one cert, not
a mapper bug (no code change warranted).
Combining all three found causes (window orientation, Table 11, shower
default): SAP 72.4567 vs Elmhurst's precise 72.0681 — residual 0.39,
~91% of the original 4.26-point gap now precisely explained.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Walked the worksheet section-by-section (dimensions, ventilation, fabric,
internal/solar gains, MIT, space-heating requirement, fuel cost) against
the calculator's matching intermediates. Internal gains and heat loss
matched closely, but solar gains (worksheet line 83) was 2.2x off in
January (56.9 W vs our 123.4 W) — traced to the Elmhurst BUILD entering
all 12 real windows (3 orientations: NW 7.05 m2, NE 1.21 m2, SE 7.06 m2)
as a single synthetic 15.32 m2 "North" group, understating solar gain.
Verified by reproducing both build artifacts in the calculator: real
windows + real Table-11 gating = 76.33 (our answer, matches lodged 76
exactly); collapsing to a synthetic single-North window + forcing Table
11 on = 72.62, reproducing Elmhurst's 72 almost exactly. Confirms neither
residual is a mapping or calculator bug — one is a deliberate,
regression-tested spec choice (Table 11) and the other is an artifact of
how this specific Elmhurst reconciliation build was entered.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The prior comment blamed a stale build-side combi artifact (already fixed
this session) and my earlier conversational claim that Elmhurst's overall
SAP used regional weather was wrong too — verified the worksheet's (5)
dwelling volume and wind table match our UK-average rating cascade exactly.
The actual, now-quantified driver: Elmhurst's worksheet (201)/(202)/(215)
show it unconditionally applies SAP 10.2 Table 11's 10% secondary/portable-
electric-heater fraction based on main heating category alone, with no
secondary lodged on the cert. Our `_secondary_fraction` deliberately gates
this on an actual lodged/forced secondary (see the adjacent S-B30 note:
applying it unconditionally regressed the full 1000-cert corpus MAE by
+0.16). Forcing Table 11 on for just this cert moves 76.33 -> 73.62 (~62%
of the 76.33-vs-72 gap) — confirms this, not a mapping error, drives the
residual. Documented so the next reader doesn't re-litigate it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per the PR #1439 handoff: swept every cert now sitting at |Δ| in [1.0, 2.0)
(58 certs) using the cost-vs-demand signature bucketer (why_diverge.py's
logic) plus field_bias.py's full-corpus subgroup scan (re-run clean after
the two engine fixes above — no |meanΔ|>=0.5 systematic subgroup with
coherent median).
Breakdown: 17 room-in-roof (already spec-mandated/worksheet-validated per
PRs #1440/#1441), 7 electric cost/tariff variants (spec-faithful vs lodged,
consistent with the diagnosed electric cluster), 4 non-electric cost
residuals (spec-faithful), ~26 non-electric fabric/demand certs. Manually
inspected geometry (floor areas/perimeters/heights, wall/roof codes,
window/door counts) for the 4 largest fabric/demand outliers in the band
(100031768368, 100070450818, 100110097281, 100051051866) — no data-entry
anomaly comparable to the earlier 12109191 decimal-floor-area bug. This
confirms the handoff's "our calc faithful, lodged differs" pattern holds
across the band; no engine bug survived the pass. Notes appended per-cert
in worklist.md (`<-`, preserved by build_worklist.py reruns).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ADR-0048 records why a system-replacing heating override must emit a
complete companion set — category and control archetype-forced for
coherence, fuel and meter deferred where multiple values are valid, and
an unmapped companion logged rather than silently inherited. Adds the
Heating Companion Set glossary term to CONTEXT.md.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
ventilation(): the cert lodges no extract-fan count and RdSAP 10 Table 5's
age-band B default is 0, but the build entered 1 — inflating Elmhurst's own
(8)/(21) infiltration lines relative to both the cert and our engine.
space_heating(): switched from the generic "Combi condens" SAP-Table dialog
code (84% efficiency, no PCDB record) to elmhurst_lib.set_pcdb_boiler(18908)
via clear_main_heating_code — resolves the exact lodged product (Worcester
Greenstar 4000, 88.70%) and its correct keep-hot classification (None),
matching the SAP engine's own PCDB lookup and removing the "Standard Combi"
keep-hot artifact the reused generic code carried.
Also corrected the file's stale docstring (described a different property
entirely — mid-terrace/250mm/DUAL meter/11 windows/lodged 63 — left over
from a copy-paste).
Verified against the refreshed worksheet: (21) shelter-adjusted ACH 0.6938
now EXACT vs our engine's ventilation_from_cert; (61) combi loss monthly
kWh matches ours to ~0.01 kWh (was carrying a ~360 kWh/yr keep-hot artifact).
Both open items from the PR #1439 handoff are resolved.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A system-replacing override whose category or control is not yet mapped
now logs an error naming the archetype and code, so the incomplete
companion set (which otherwise silently inherits the replaced system's
value) is visible for review — log-and-continue, matching flag_fuel_mismatch.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Control 2601 (SAP Table 4e Group 6 room-heater, +0.3 C conservative
default) now overlaid for electric room heaters, matching the gas/oil/
solid siblings, so a replaced storage heater's manual charge control
2401 (+0.7 C) no longer survives and over-warms the modelled dwelling.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_has_suspended_timber_floor_per_spec only read the Main bp's per-part
floor_construction_type lodgement; the gov-API mapper frequently leaves
that None even when the global epc.floors[].description carries an
explicit "Suspended, ..." observation. _main_floor_u_value already fell
back to this joined description for the U-value calc — the infiltration
rule did not, so a genuinely suspended-timber floor silently entered
(12)=0 instead of 0.2 unsealed. Extracted the shared
_effective_floor_description helper and added a tri-state resolver
(explicit lodgement -> description, excluding "not timber" -> Table 19
footnote-1 age-A/B default) so both paths agree.
Cert 100061275133 (Elmhurst-validated build, PR #1439 handoff): engine
77.24 -> 76.33, now an exact match to lodged (76). Corpus gauge 77.7% ->
77.8% within-0.5, MAE 0.637 -> 0.636; floors ratcheted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Category 10 (SAP Table 4a Room heaters) now overlaid for electric room
heaters (691-701), so a replaced storage heater's category 7 no longer
survives onto the effective cert and mis-bills via the Table 12a resolver.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>