Commit graph

8288 commits

Author SHA1 Message Date
Daniel Roth
316a112258 Rate gas room-heater main systems at Table 4a code 603 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
f5eb8af534 Bill balanced-flue gas fires at Table 4a code 609 (58%) 🟩
#1629: Wythenshawe 163→164 computed; within-0.5 75.6%, MAE 0.737 —
ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
4a0f1fe939 Bill balanced-flue gas fires at Table 4a code 609 (58%) 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
6262f6594d Bill title-cased dual-fuel secondary heaters at Table 32 code 10 🟩
#1628: fixture 500796700868 re-blocks on a later label
(first-exception-hit); metrics unchanged, ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
4af086112a Bill title-cased dual-fuel secondary heaters at Table 32 code 10 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
223edb0066 Bill pre-1980 open-fronted gas fires at Table 4a code 601 (50%) 🟩
#1627: Wythenshawe 162→163 computed; within-0.5 75.5%, MAE 0.741 —
ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
951913f1de Bill pre-1980 open-fronted gas fires at Table 4a code 601 (50%) 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
e21064dc7a Bill loose-jacket cylinders their Table 2 Note 1 storage-loss factor 🟩
Follow-on surfaced by #1626: fixture 500796646644 progressed past the
2404 conflict onto cylinder insulation 'Loose jacket' → code 2 (gov-API
coding, Elmhurst 'Jacket' sibling). Wythenshawe 161→162 computed
(32.6 vs pre 34); ratchets hold at 75.3%/0.744.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
c17a42afc5 Bill loose-jacket cylinders their Table 2 Note 1 storage-loss factor 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
ea4b7938e7 Resolve HHR-control ticks on manual-entry non-HHR storage heaters to 2402 🟩
#1626: ground truth resolved per the issue's option 3. The accredited
cert 0764-2894-7173-2720-5535 (62 Mayfair Road, UPRN 77066640 — the
blocked Wythenshawe fixture's dwelling) lodges 402 + 2402 for the same
heater description, and RdSAP 10 p.80 (item 7-3) requires a PCDB index
for any HHR lodgement — absent one, the surveyed type field is
authoritative and 2404 downgrades to 2402 (automatic charge control,
preserving the tick's automatic-charging semantics). Applies only to
the mapped non-HHR types (402/404); any other pairing still fails loud.
LRHA fixture 505091686590 (Fan storage heater, same slip) computes
64.0 vs pre 65; LRHA 76→77 computed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
1587db61f2 Resolve HHR-control ticks on manual-entry non-HHR storage heaters to 2402 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
be1f69ccd4 Suppress floor heat loss for internal floors over the same dwelling 🟩
#1625: 'Same dwelling below' → the "(another dwelling below)" party-
floor suppression string, mirroring the gov-API code-8 precedent
(RdSAP 10 §3: an internal floor between heated storeys has no floor
heat loss). Wythenshawe 151→161 computed; 7/10 newly-unblocked land
within 0.5 — ratchets re-baselined 0.76/0.72 → 0.75/0.75 for the two
tail entries (−3.3/−5.5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
6356adb523 Suppress floor heat loss for internal floors over the same dwelling 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
01cacc579a Rate unthermostated room heaters via Table 4e Group 6 code 2601 🟩
#1624: Wythenshawe 149→151 computed. 500767954156 lands within 0.5;
500797465814 is a −8.8 tail entry — MAE ceiling re-baselined 0.67→0.72
per the coverage-growth convention (within-0.5 floor 0.76 holds).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
8b242b7da8 Rate unthermostated room heaters via Table 4e Group 6 code 2601 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
6750e48609 Rate MVHR dwellings via Table 4g and biomass heat networks via Table 12 code 43 🟩
#1637: 'MV - Heat Recovery' → MVHR kind (Table 4g default 46.2% heat
recovery — PasHub lodges no PCDF product/wet-rooms/duct data, so these
land in the accuracy tail as the issue predicts). Unblocking them
surfaced 4 biomass heat networks whose fuel label 'Heat from boilers -
biomass' passed through raw to the calculator's MissingMainFuelType —
now mapped to Table 12 code 43, and any other uncovered community fuel
strict-raises UnmappedPasHubLabel at the boundary (ADR-0015).
LRHA 61→76 computed / 28 blocked / 0 errored, within-0.5 43.4%,
MAE 2.985 — ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
38e9ebd5c7 Rate MVHR dwellings via Table 4g and biomass heat networks via Table 12 code 43 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
7a81fbfa45 Rate heat-network charging controls 2306/2314/2313 per Table 4e Group 3 🟩
#1636: the 6 single-line-label fixtures unblock and re-block on later
labels (MVHR/cylinder); the 6 line-wrap-truncated '…room thermostat
and' fixtures still need the extractor fix tracked under #1622.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
f135e96e2e Rate heat-network charging controls 2306/2314/2313 per Table 4e Group 3 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
9d761f6ad1 Score heat-pump dwellings via Table 4e Group 2 controls and Appendix N efficiency 🟩
#1635: 'Programmer, room thermostat and TRVs' on a heat pump → 2210
(PCDB heat_pump_controls), and the lodgement now carries Table 4a
category 4 — without it the calculator's Appendix N3.6/N3.7 gate never
fired and the PCDB heat pump was billed as 100%-efficient direct
electric (6.0/18.5 vs pre 62/57). With the category threaded the two
LRHA WAVE 3 fixtures score 52.1/56.9 (the latter within 0.5).
LRHA 59→61 computed, within-0.5 42.6%, MAE 2.830 — ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
436675d64f Score heat-pump dwellings via Table 4e Group 2 controls and Appendix N efficiency 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
70f5172aa2 Resolve Medium cylinder band to Table 28 fixed 160 L (code 3) 🟩
#1634: LRHA WAVE 3 51→59 computed, within-0.5 42.4%, MAE 2.757 —
ratchets hold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
7ca02588ab Resolve Medium cylinder band to Table 28 fixed 160 L (code 3) 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
e0b92016a8 Bill secondary water/oil-filled radiators as PCDB 694 electric room heaters 🟩
#1633: fixture 497714783467 re-blocks on its next label (first-exception-hit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
2da0dda9d4 Bill secondary water/oil-filled radiators as PCDB 694 electric room heaters 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
3b2e6e348a Score heating-oil dwellings via SAP main-fuel code 28 🟩
#1632: LRHA WAVE 3 45→51 computed. Newly-unblocked oil configs land
outside 0.5 (coverage growth per module convention) — within-0.5 floor
re-baselined 0.46→0.41 at 41.2%/MAE 2.948.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
bb604d79bf Score heating-oil dwellings via SAP main-fuel code 28 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:32 +00:00
Daniel Roth
2a68fc2a76 Map triple glazing 2002-2021 windows to SAP10 code 9 🟩
#1630: 11 LRHA WAVE 3 fixtures re-block on later labels (first-exception-hit).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:31 +00:00
Daniel Roth
cff4095cfd Map triple glazing 2002-2021 windows to SAP10 code 9 🟥
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 16:41:31 +00:00
Daniel Roth
8f9b2fe2c5
Merge pull request #1638 from Hestia-Homes/add-herdr-to-devcontainer
Add herdr to backend devcontainer
2026-07-16 17:17:05 +01:00
Daniel Roth
b173fc437a Add herdr to dockerfile 2026-07-16 16:35:58 +01:00
KhalimCK
324397721b
Merge pull request #1623 from Hestia-Homes/feature/sitenotes-mapping-wythenshaw
Wythenshawe Pashub SiteNotes mapping tests
2026-07-16 15:56:59 +01:00
Daniel Roth
d844bc6df2 PasHub SAP accuracy: pin Wythenshawe cohort (149/168 computable) 🟩
Add pashub_accuracy_wythenshawe fixtures + a sibling accuracy module,
built from project_code
[Wythenshawe WH:SHF RAs - WH:SF - 240426 - 494493718748] the same way as
LRHA WAVE 3 (#1620). First run: 149 computed / 19 blocked / 0 errored,
within-0.5 76.5%, MAE 0.665. Ratchets baselined to this cohort; the 19
blocks are separately-ticketed mapper-label gaps (floor 'Same dwelling
below' ×10 dominating), not tuning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 14:49:17 +00:00
Daniel Roth
80bba24598
Merge pull request #1621 from Hestia-Homes/feat/1619-pashub-storage-heaters
PasHub: score electric-storage & room-heater dwellings (Table 4e Group 4/6) — closes #1619
2026-07-16 15:34:52 +01:00
KhalimCK
2d0d04bb89
Merge pull request #1620 from Hestia-Homes/pas-accuracy-lincs-rural
Lincs Rural Pashub SiteNotes mapping tests
2026-07-16 15:32:05 +01:00
Daniel Roth
3e2509fb7d PasHub scores electric-storage & room-heater dwellings (Table 4e Group 4/6) 🟩
Teaches the pashub `from_site_notes` mapper the electric-storage-heater and
room-heater families, following the existing boiler/heat-network split exactly
(fix at the mapper boundary, ADR-0015 — never mis-rate, never strict-raise deep
in the calculator). Adds:

- Table 4e Group 4 storage charge-control codes (2401/2402/2404) and Group 6
  room-heater control codes (2602/2605), each gated on its own system group so a
  control label never takes a wrong-group 2xxx code.
- The Table 4a system code from the surveyed heater type lodged in the "Heating
  System (Other)" field (`community_heat_source`): Fan storage 404, slimline
  402, PCDF-Search product ⇒ HHR 409 (RdSAP 10 p.80), room heaters 691/694.
- A 2404⇔409 coherence guard: high-heat-retention controls on a non-HHR storage
  type is a surveyor contradiction and fails loud rather than rating a mismatch.

All codes taken from the SAP 10.2 spec (14-03-2025 PDF) and already present in
the calculator's inventories — no calculator change.

LRHA WAVE 3 (lincs rural) accuracy: 8 computed / 96 blocked → 45 computed / 59
blocked / 0 errored (within-0.5 46.7%, MAE 2.989); ratchets re-baselined to the
new coverage. Guinness cohort (208) + gov-API corpus unchanged; pyright --strict
adds zero new errors.

Closes #1619

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 13:30:07 +00:00
Daniel Roth
d557e1b0b4 make pashub accuracy test more generic and add files for lincs rural 2026-07-16 11:22:39 +00:00
KhalimCK
e75144afb3
Merge pull request #1617 from Hestia-Homes/fix/pashub-semi-exposed-floor
PasHub SAP accuracy: semi-exposed-unheated floor → Table 20 (+ Walsden/Paxton fixtures)
2026-07-16 02:01:07 +01:00
Khalim Conn-Kowlessar
6c4f73cc91 PasHub SAP accuracy: refresh 5 Paxton fixture to the current V5 (MEV) re-survey 🟩
5 Paxton Place (deal 507639151845, uprn 10070864419) had a STALE fixture.
The same PAS Hub survey (report B74AA5A4-…, inspected 29 Jun 2026) has two
accredited revisions in S3: V2 (uploaded 6 Jul, ventilation "Natural",
SAP 80) and V5 (uploaded 14–15 Jul, ventilation "Mechanical Extract -
Centralised", SAP 76 — the current version). Our committed fixture was the
superseded V2; the portfolio-838 oracle tracks the latest V5 (76). Our
engine faithfully reproduces BOTH (V2 → 80.4, V5 → 75.6) — the +4.38 miss
vs the DB oracle was a fixture-version mismatch, NOT an engine over-rate
(a parallel over-credit sweep found no spec-correct from_site_notes lever;
every channel is faithful).

Refreshed the fixture to the V5 PDF (image-stripped, text layer preserved,
6.7MB→0.27MB, per scripts/build_pashub_accuracy_fixtures.py) and set the
manifest to C76. 5 Paxton flips from the cohort's largest miss to a
within-0.5 hit: DB-oracle gauge 86.9%→87.4% within-0.5, MAE 0.348→0.327.
Pinned via test_paxton_fixture_is_v5_resurvey_sap_76 (asserts a literal 76
against the V5 fixture) — a canary, because hubspot_deal_data.pre_sap is
still stale at C80 and a fixture-builder rerun would revert the manifest.

Confirmed against pashub: the current survey is SAP 76 (Khalim).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 00:52:33 +00:00
Khalim Conn-Kowlessar
d3f36d78ac PasHub SAP accuracy: pin 13 Walsden to its re-survey SAP 64, not the colliding 68 🟩
13 Walsden (deal 499630239947, uprn 77179782) has TWO distinct gov-EPC
assessments: the PAS Hub site-note re-survey we parse (26 May 2026,
accredited SAP 64, backed by rd_sap_site_note files) and a SEPARATE
later lodged cert (24 Jun 2026, SAP 68, registered, no site-note). The
portfolio-838 baseline latched onto the 24-Jun SAP-68 cert; our engine
models the survey it was given and reproduces its own accredited 64
(64.19). 6 of 7 Walsden Street homes have pbp oracle == PAS Hub survey
SAP exactly — #13 is the lone collision.

A durable regression pin (asserts our SAP within 0.5 of a literal 64,
not the manifest value the fixture-builder can revert to a colliding DB
row) documents the provenance so nobody "corrects" the target to 68.
13 Walsden is a known re-survey-diverges outlier, not an engine
under-rate; confirmed against pashub (Khalim, 2026-07-15e).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 00:52:33 +00:00
Khalim Conn-Kowlessar
4c0ccad882 PasHub SAP accuracy: semi-exposed-unheated floor → Table 20, not §5.14 🟩
`_PASHUB_FLOOR_EXPOSURE` mapped the surveyed "Semi Exposed (unheated)"
floor label to `is_above_partially_heated_space` (RdSAP §5.14, constant
U=0.7). A floor semi-exposed to an enclosed UNHEATED space belongs in
§5.13 Table 20 `u_exposed_floor` (band-B as-built U=1.20). §5.14's U=0.7
is reserved for a floor above a *partially* heated space. #1602
transposed the two branches; the too-low U under-counted floor loss on
the 9 label-carrying cohort fixtures → a shared over-credit.

Triangulated against all three siblings + the calculator docstring: the
gov-API code-2 "To unheated space" (mapper.py:4797) and Elmhurst
`_is_floor_exposed_to_unheated_space` (mapper.py:5970) both route to
Table 20; rdsap_uvalues.py:1416 documents Table 20 as collapsing exposed
and semi-exposed-to-unheated into one lookup. One-line data flip,
from_site_notes-only (gov-API RdSAP corpus untouched, still 78.9%).

Adjacent Ronald St mid-terrace pair (the clustered signal): 10 Ronald
60.35→59.02 (oracle 59), 12 Ronald 60.79→59.36 (oracle 59). Cohort vs
DB oracle (portfolio 838 effective_sap) 83.3%→86.9% within-0.5, MAE
0.377→0.348, no built form regresses, all 7 verified dwellings unchanged
(none carry the label). pashub harness 79.5%→82.4%, MAE 0.389→0.367;
ratchets tightened 0.78→0.82 / 0.40→0.37. pyright zero-new.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 00:52:33 +00:00
KhalimCK
04b7c26f67
PasHub SAP accuracy: infiltration inputs + immersion DHW + lights/lobby/heat-network (#1615)
* Electric-immersion DHW: bill at 100%, not the space boiler's efficiency 🟩

A separate electric immersion heater (SAP water-heating code 903) is 100%
efficient (SAP 10.2 Table 4a) and the space-heating boiler provides no water
heating, so Appendix D2.1 Eq D1 (the boiler seasonal-efficiency cascade) must
not apply to it. But `_water_heating_main` resolves DHW to the SPACE main — a
gas/oil boiler keeps its PCDB record — so three water-efficiency branches in
cert_to_inputs billed the immersion-heated cylinder at the boiler's ~87% summer
efficiency (a mongrel: electric fuel price x gas-boiler efficiency):

  1. the scalar `water_eff = water_pcdb_main.summer_efficiency_pct / 100`,
  2. the SAP §9.4.11 / Table 4c(2) -5pp no-interlock adjustment, and
  3. the Eq D1 (winter, summer) seasonal pair from `pcdb_main`.

Gate all three on `not dhw_is_electric_immersion`; the correct immersion path
(`_water_efficiency_with_category_inherit` -> 1.0, Eq D1 off) then applies,
mirroring the Table 3 zero-primary-loss gate already present for WHC 903.

General bug — fires for any WHC-903 dwelling whose space main is a PCDB gas/oil
boiler. It surfaced via the PasHub campaign's #1600 no-water-heating default
(WHC 999 -> 903) on a gas-combi dwelling: 58 Hackle St M11 4WU, SAP 55.30 ->
57.67 (pre_sap 58, verified 59).

Guardrails: the gov-API RdSAP corpus IMPROVES 78.8% -> 78.9% within-0.5, MAE
0.625 -> 0.622 (a handful of corpus certs with a boiler space main + electric
immersion move closer to accredited) — MAE ceiling ratcheted 0.626 -> 0.625.
Regression pinned in test_cert_to_inputs (RED before / GREEN after). pyright
0-new (cert_to_inputs baseline 30).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* PasHub SAP accuracy: thread low-energy lights + draught lobby (from_site_notes) 🟩

Two systematic silent-drops in the PAS Hub `from_site_notes` path, each a field
the gov-API/Elmhurst mappers thread but site-notes dropped, letting a favourable
default reach the SAP-10.2 calculator. Validated against the correct pashub
oracle (property_baseline_performance.effective_sap_score, portfolio 838):
cohort within-0.5 55.1% → 62.6%, MAE 0.599 → 0.521.

- Low-energy lights: when "exact LED/CFL known = No", PAS Hub lodges an aggregate
  "Number of fixed low energy lights?" count. Previously dropped (no dataclass
  field / extractor key / mapper thread) → calculator saw 0 low-energy bulbs and
  applied the pessimistic L5b/L8c no-data default, under-rating SAP. Now threaded
  into low_energy_fixed_lighting_bulbs_count, mirroring from_elmhurst_site_notes.
  ~6% of the cohort; resolves 58 Hackle (−0.43 vs oracle 59 with #1615).
- Draught lobby: _map_sap_ventilation set only the legacy `draught_lobby` field,
  never the canonical `has_draught_lobby` §2 (13) gate the cascade reads, so the
  surveyed lobby was ignored and infiltration over-stated. Now mirrors Elmhurst.

Two other audited levers were REJECTED against the pashub oracle (they matched
the gov-cert/RdSAP convention but pashub does not apply them): percent_draughtproofed
(cohort 30.8%) and the §A.2.2 assumed secondary heater (19.2%). A heat-network
control-code fix (2306→2303 for 16 Bingley) is HELD pending spec/Elmhurst
adjudication — it contradicts ADR-0053; see the NOTE on _PASHUB_HEAT_NETWORK_CONTROL_TO_SAP10.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* PasHub heat-network control: room-thermostat-only maps to 2308, not 2306 🟩

The Table 4e Group 3 label "charging linked to use of community heating, room
thermostat only" was mapped to 2306 — the linked-to-use *with-TRVs* code
(control type 3, space charging 1.00). The label explicitly excludes TRVs, so
it is control type 2 / space 1.05 = code 2308/2309 (linked-to-use → DHW 1.00).
2306 asserted TRVs the survey doesn't have and over-rated the cohort's sole
heat-network dwelling (16 Bingley Close 56.89 → 54.01 vs pashub oracle 52).

Verified against SAP 10.2 Table 4e as encoded in cert_to_inputs.py
(_CONTROL_TYPE_BY_CODE 2308→2, space-charging 2308→1.05, DHW 2308→1.00) and the
RdSAP control-label vocabulary in MainheatControlAttributes.py. 2303 (the earlier
audit's guess) is rejected: it is a flat-rate code (DHW 1.05) whose oracle match
was a coincidence of two offsetting spec violations. The residual +2.0 to oracle
52 is the documented SAP-10.2-engine-vs-lodged offset, not a fuel/flags gap
(those were threaded by the #1590 follow-up) — supersedes the ADR-0053 /
HANDOVER_838 "community fuel/flags" attribution.

16 Bingley is the only heat-network fixture in portfolio 838, so this moves one
fixture strictly toward its oracle. Harness ratcheted: within-0.5 0.51→0.58,
MAE 0.625→0.521 (observed 58.5% / 0.520 with all three 2026-07-15 levers).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* PasHub SAP accuracy: restore 3 dropped §2 infiltration inputs (from_site_notes)

`from_site_notes` uniquely dropped three ventilation inputs that the gov-API
and Elmhurst sibling mappers all set, causing a systematic cohort-wide SAP
under-rate vs the company's own accredited SAP-10.2 certs
(property_baseline_performance.effective_sap_score, portfolio 838):

1. percent_draughtproofed — never set, so §2(15) window infiltration was
   pinned at its 0.25-ACH worst case on every dwelling. Reconstructed as the
   area-weighted % of draught-proofed windows (mirrors Elmhurst
   `draught_proofing_percent`). Dominant term.
2. Upper-storey +0.25 m joist void — omitted; now added, matching
   `_UPPER_FLOOR_HEIGHT_ADD_M` on the gov-API/Elmhurst paths. This
   RE-ADJUDICATES #1601 ("keep raw"): that call was confounded by the
   then-present draught-proofing drop suppressing every verified dwelling.
3. sheltered_sides — left None → calculator's flat default of 2, which
   over-shelters end/semi/detached (RdSAP §S5 = 1/1/0). Now derived from
   built form.

The three are NON-ADDITIVE — each overshoots alone (which is why all three
were previously rejected individually) — but together they land all 7
verified ground-truth dwellings toward truth (none regress) and every built
form near zero. Cohort 62.1% -> 83.3% within-0.5, MAE 0.507 -> 0.377.

Guardrails: gov-API RdSAP corpus unchanged (78.9%, these are from_site_notes-
only helpers). pashub harness 58.5% -> 79.5% / MAE 0.520 -> 0.389; ratchets
tightened 0.58->0.78 and 0.521->0.40. pyright zero-new (mapper baseline 39).
New focused tests in TestFromSiteNotesInfiltrationFixes cover all three
fields incl. area-weighting and the built-form shelter map; goldens updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 00:30:55 +01:00
KhalimCK
ccba02b51a
Merge pull request #1614 from Hestia-Homes/feat/1602-1603-pashub-floor-exposure-alt-walls
PasHub floor exposure + alternative walls + extension floor (#1601 keep-raw, #1602, #1603)
2026-07-15 16:52:13 +01:00
Khalim Conn-Kowlessar
6fd0393a4e Tighten pashub accuracy ratchets to 0.51 / 0.625 🟪
#1602 (floor exposure flags) + #1603 (alternative walls + extension floor
construction) move the Guinness 205 cohort within-0.5 50.2% -> 51.2% and MAE
0.653 -> 0.624. Lock the gain: floor 0.50 -> 0.51, ceiling 0.653 -> 0.625.
#1601 note updated from HELD to RESOLVED (keep-raw).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:46:06 +00:00
Khalim Conn-Kowlessar
5324ae0e57 PasHub floor exposure + alternative walls + extension floor 🟩
Resolve #1601 and land #1602/#1603 on the merged-#1609 tree, adjudicated
against Khalim's verified ground truth (not pre_sap).

#1601 (upper-floor +0.25 m joist void) — RESOLVED as keep-raw. The
gov-API/Elmhurst mappers add 0.25 m to upper-storey heights because their
lodged height is a clear internal ceiling. Against verified truth RAW beats
+0.25 on all 7 verified dwellings (16 Stillwater raw -0.35 within-band vs
+0.25 -0.75; every verified property is already under truth and +0.25 only
lowers SAP). pashub surveys internal dimensions (202/205 "Measurements
Location: Internal") and its upper-ground height gap is modal 0.00, so the
joist void is not differentially present and a blanket +0.25 is unsafe.
_map_floor_dimensions keeps the raw surveyed height with a RESOLVED note.

#1602 — semi-exposed / exposed floor exposure. The surveyed "Floor type"
"Semi Exposed (unheated)" now sets is_above_partially_heated_space (RdSAP
§5.14 U=0.7) and "Exposed Floor" sets is_exposed_floor (§5.13 Table 20), on
the lowest storey (floor==0) only, mirroring the gov-API/Elmhurst siblings.
New strict-raise _pashub_floor_exposure (ADR-0015).

#1603a — alternative walls. New AlternativeWall survey dataclass +
extract_alternative_walls (the "Alternative Wall"->"Windows" section) +
_map_pashub_alternative_walls -> sap_alternative_wall_1/2. The cascade
deducts each alt-wall area from the part's main opaque wall (no double
count), so a mixed-facade dwelling is billed at each sub-area's own
construction. The alt-wall block lodges "As Built" (capital B) — aliased to
the existing default insulation code.

#1603b — extension floor construction. ExtensionConstruction gains a floor
block (parsed like the main building) and _map_extension_building_part now
threads floor_type/construction/insulation/u_value_known, which the main
path already did and the extension silently dropped.

Cohort: within-0.5 50.2% -> 51.2%, MAE 0.652 -> 0.624, 0 strict-raise
errors across all 205. Verified-truth safe: none of the 7 verified
dwellings have alt walls, and #1602 moves the one it touches (2 Philips
exposed ext floor) by -0.00. pyright 0-new (mapper baseline 39). Goldens
test_full_building_construction + end_to_end EXTENSION_1 updated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 15:46:06 +00:00
Daniel Roth
c54ee4cad7
Merge pull request #1610 from Hestia-Homes/fix/1606-water-only-c6-half-standing-charge
[1592] Include the C6 half standing charge for water-only heat networks
2026-07-15 15:21:23 +01:00
Daniel Roth
7fc4e6be52 Merge branch 'main' into fix/1606-water-only-c6-half-standing-charge 2026-07-15 14:15:18 +00:00
KhalimCK
85e536bda7
Merge pull request #1609 from Hestia-Homes/feat/1596-pashub-two-clusters
PasHub SAP accuracy: three extraction silent-drop fixes (within-0.5 23.9% → 50.2%)
2026-07-15 15:08:33 +01:00
Khalim Conn-Kowlessar
644bc300a6 Merge remote-tracking branch 'origin/main' into feat/1596-pashub-two-clusters
# Conflicts:
#	backend/documents_parser/tests/test_pashub_sap_accuracy.py
2026-07-15 14:02:15 +00:00
Daniel Roth
589eedba8a Cite C6 rather than C3.2 for the heat-network standing charge rule 🟪
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 13:53:59 +00:00