mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs: handover for cert 9501 (flat exposure) + HP workstream
Captures session state after cert 0330 closed both Summary and API
Layer 4 1e-4 gates (Slices 96-98). Cert 9501 fixtures are staged
(commit 5d1778ac) but the Summary path is RED at Δ -5.25 SAP because
the cert is a flat with RR + party-floor / party-ceiling — a
fundamentally different cascade shape from the boiler houses we've
validated.
Handover quantifies the cascade-component gaps (-69.92 W/K on walls
because RR gables aren't surfaced, +9.25 W/K on floor because the
party-floor exposure isn't recognised, +7.36 W/K on party walls
because U_party=0 isn't being applied), lists the 4 fixes likely
needed in slice order, and leaves the heat-pump workstream sketch
intact for when the user gives the go-ahead.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
5d1778ac4e
commit
158c08f10f
1 changed files with 222 additions and 0 deletions
222
domain/sap10_calculator/docs/HANDOVER_CERT_9501_AND_HEATPUMPS.md
Normal file
222
domain/sap10_calculator/docs/HANDOVER_CERT_9501_AND_HEATPUMPS.md
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
# Handover — Cert 9501 flat-exposure + heat-pump workstream
|
||||
|
||||
You're picking up branch `feature/per-cert-mapper-validation` after
|
||||
the cert 0330 boiler workflow landed (Layer 4 1e-4 gate GREEN on both
|
||||
Summary and API paths, mirroring cert 001479). Two boiler certs are
|
||||
now validated end-to-end against worksheets at 1e-4. The third boiler
|
||||
cert (9501) is staged but RED at Δ -5.25 SAP because it surfaces a
|
||||
new class of mapper gap: **flat-specific exposure**.
|
||||
|
||||
## State at session start
|
||||
|
||||
Recent commits:
|
||||
|
||||
```
|
||||
8443c770 Slice 98: API path shower-counts + window-rounding → cert 0330 1e-4
|
||||
aa6645e3 Slice 97: API glazing_type=2 → RdSAP 10 Table 24 (DG 2002-2021)
|
||||
da5e7196 Slice 96: flat-roof U-value defaults — RdSAP 10 §5.11 Table 18 col (3)
|
||||
5d1778ac chore: stage cert 9501 fixtures (second boiler validation cert)
|
||||
17646c8a chore: stage cert 0380 fixtures (HP pilot — deferred workstream)
|
||||
460f1735 chore: stage cert 0330 fixtures (boiler pilot)
|
||||
```
|
||||
|
||||
Test baselines you should see (197 pass + 9 pre-existing 001479
|
||||
Layer 1 fails):
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/workspaces/model python -m pytest \
|
||||
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \
|
||||
domain/sap10_ml/tests/test_rdsap_uvalues.py \
|
||||
datatypes/epc/schema/tests/test_schema_loading.py \
|
||||
--no-cov -q
|
||||
```
|
||||
|
||||
Layer 4 1e-4 gates passing:
|
||||
|
||||
- `test_api_001479_full_chain_sap_matches_worksheet_pdf_exactly`
|
||||
- `test_api_0330_full_chain_sap_matches_worksheet_pdf_exactly` ← landed this session
|
||||
- `test_summary_001479_full_chain_sap_matches_worksheet_pdf_exactly`
|
||||
- `test_summary_0330_full_chain_sap_matches_worksheet_pdf_exactly` ← landed this session
|
||||
- 000477 / 000516 cohort chain tests
|
||||
|
||||
## Cert 9501 — staged but RED (Δ -5.25 SAP)
|
||||
|
||||
Fixtures committed in `5d1778ac`:
|
||||
- API JSON: `domain/sap10_calculator/rdsap/tests/fixtures/golden/9501-3059-8202-7356-0204.json`
|
||||
- Summary PDF: `backend/documents_parser/tests/fixtures/Summary_000784.pdf`
|
||||
- Worksheet (reference): `sap worksheets/Additional data with api/9501-3059-8202-7356-0204/dr87-0001-000784.pdf`
|
||||
|
||||
Cert shape (per worksheet header):
|
||||
- Property type: **Flat, Mid-Terrace** (mid-floor — `not` top-floor as
|
||||
the prior handover claimed)
|
||||
- Storeys (building): 4
|
||||
- Age band: B
|
||||
- TFA: 113.08 m²
|
||||
- Heating: mains-gas boiler, PCDB idx 19007 (Vaillant)
|
||||
- Worksheet target unrounded SAP: **68.5252**
|
||||
|
||||
### Cascade-component diff (Summary path vs worksheet)
|
||||
|
||||
```
|
||||
TFA: 113.08 = 113.08 ✓
|
||||
walls: 148.89 vs 218.81 (Δ -69.92 ← BIG — missing RR gables)
|
||||
roof: 18.10 = 18.10 ✓ (Table 18 age B col-(3) +
|
||||
col-(1) compound — fine)
|
||||
floor: 9.25 vs 0.00 (Δ +9.25 ← FLAT GROUND-FLOOR PARTY)
|
||||
windows: 25.83 = 25.83 ✓
|
||||
doors: 5.55 = 5.55 ✓
|
||||
party: 7.36 vs 0.00 (Δ +7.36 ← worksheet U_party=0 for flat)
|
||||
bridges: 25.00 vs 28.39 (Δ -3.39 ← downstream of (31) shrink)
|
||||
(37) tot: 239.98 vs 296.68 (Δ -56.70 ← composite)
|
||||
|
||||
ECF: 2.6326 vs 2.2563 (too high; SAP too low by 5.25)
|
||||
```
|
||||
|
||||
### Worksheet element decomposition (line 187-205)
|
||||
|
||||
```
|
||||
Element Net Area U A x U
|
||||
(26) Doors uninsulated 1 1.85 3.00 5.55
|
||||
(27) Windows 1 10.60 2.44 25.83
|
||||
(28a) Ground floor Main 67.58 0.00 0.00 ← PARTY
|
||||
(29a) External walls Main 99.26 1.70 168.74
|
||||
(29a) Roof room Main Gable Wall 1 13.50 1.70 22.95 ← RR
|
||||
(29a) Roof room Main Gable Wall 2 15.95 1.70 27.12 ← RR
|
||||
(30) Roof room Main Flat Ceiling 1 5.50 0.19 1.045 ← RR
|
||||
(30) External roof Main 42.63 0.40 17.05
|
||||
(31) Total net area = 189.29 m²
|
||||
(33) Fabric heat loss = 268.28
|
||||
(32) Party walls Main 52.54 0.00 0.00 ← PARTY
|
||||
(32d) Dwelling below Main 6.85 — — ← PARTY
|
||||
(35) TMP = 250
|
||||
(36) Bridges (0.150 × 189.29) 28.39
|
||||
(37) Total fabric heat loss 296.68
|
||||
```
|
||||
|
||||
### Localised mapper gaps
|
||||
|
||||
The Summary path's `EpcPropertyData` has these load-bearing wrong
|
||||
or missing fields:
|
||||
|
||||
| Field | Currently | Should be |
|
||||
|---|---|---|
|
||||
| `dwelling_type` | `"Number of Storeys: flat"` (mangled by extractor) | `"Flat"` |
|
||||
| `built_form` | `"Number of Storeys:"` (mangled) | `"Mid-Terrace"` (or similar) |
|
||||
| `sap_flat_details` | `None` | populated with the cert's flat position |
|
||||
| `sap_building_parts[0].sap_room_in_roof` | likely None | populated with the RR's gable walls + flat ceiling areas |
|
||||
|
||||
**Order of attack** (each is a slice candidate):
|
||||
|
||||
1. **Fix the Elmhurst extractor's `dwelling_type` / `built_form`
|
||||
parsing** for this Summary PDF format. Some other section of the
|
||||
PDF is bleeding into the parsed value (the "Number of Storeys:"
|
||||
prefix). The extractor's anchor for `built_form` is likely
|
||||
matching too eagerly; check `ElmhurstSiteNotesExtractor`. Don't
|
||||
guess — read the Summary_000784.pdf header section + compare to
|
||||
what `ElmhurstSiteNotesExtractor` returns.
|
||||
|
||||
2. **Populate `sap_flat_details`** in `EpcPropertyDataMapper.
|
||||
from_elmhurst_site_notes`. The cascade's `_dwelling_exposure`
|
||||
reads from this field (see
|
||||
`domain/sap10_calculator/rdsap/cert_to_inputs.py`) to gate
|
||||
floor/roof contributions per RdSAP 10 §5. For cert 9501 (mid-
|
||||
floor flat), both floor (party with dwelling below) and roof
|
||||
(party with dwelling above) should be excluded — but the cert
|
||||
does have an RR with gable walls and flat ceiling exposed
|
||||
externally, so the dwelling has SOME exposed roof.
|
||||
|
||||
3. **Populate `sap_room_in_roof`** with the RR-specific geometry:
|
||||
gable walls 13.50 + 15.95 m², flat ceiling 5.50 m². Worksheet
|
||||
lodges these as part of the Main bp's (29a) walls + (30) roof.
|
||||
Cascade reads from `sap_room_in_roof.detailed_surfaces` —
|
||||
check `worksheet/heat_transmission.py` for the surfacing
|
||||
convention.
|
||||
|
||||
4. **Re-pin or remove cert 9501 from Layer 4 tracking** once
|
||||
Summary path lands at 1e-4. The RED test was NOT committed this
|
||||
session (working-tree-only) — add the equivalent of
|
||||
`test_summary_0330_full_chain_sap_matches_worksheet_pdf_exactly`
|
||||
for cert 9501 once the gap closes.
|
||||
|
||||
### API path expected gaps (after Summary lands)
|
||||
|
||||
The API JSON for cert 9501 lodges `property_type=2` (Flat) and
|
||||
`built_form=NR`. The API mapper needs to populate `sap_flat_details`
|
||||
from `floors[]` + `roofs[]` + the GOV.UK schema's flat-specific
|
||||
fields. Probable additional gaps (same pattern as Summary):
|
||||
- `sap_flat_details` mid-floor exposure routing
|
||||
- RR detection from cert's `roofs[].description` if the cert lodges
|
||||
an attic-style roof
|
||||
|
||||
## Heat-pump workstream (cert 0380 + 6 sibling ASHPs) — DEFERRED
|
||||
|
||||
Per the user's direction, the 7 ASHP certs are deferred until the
|
||||
boiler workflow is proven. Status:
|
||||
|
||||
- Cert 0380 fixtures staged in commit `17646c8a` (worksheet target
|
||||
SAP 88.5104). Original probe showed catastrophic Δ -70 SAP on
|
||||
Summary path and Δ -18 SAP on API path — the Summary mapper
|
||||
identified the HP as an 80%-efficient boiler.
|
||||
- 6 other ASHPs share PCDB index 104568 (one uses 102421) — work
|
||||
is likely shared across them.
|
||||
|
||||
Work sketch (from the prior handover):
|
||||
|
||||
1. **API mapper**: surface `main_heating_index_number`, set
|
||||
`main_heating_category` for HPs, `main_fuel_type=29` (electric
|
||||
heat pump).
|
||||
2. **Cascade**: ensure `cert_to_inputs._main_heating_efficiency`
|
||||
reads PCDB HP COP correctly. Investigate Table 4a/4b vs PCDB
|
||||
precedence for HPs.
|
||||
3. **Fuel cost**: HW + space heating on electricity tariffs
|
||||
(Table 12) — check if the cascade has electric-tariff fuel-cost
|
||||
plumbing wired up.
|
||||
4. **Appendix N**: HP-specific efficiency adjustments (climate +
|
||||
flow temperature). Likely the biggest cascade-side gap.
|
||||
5. **Summary mapper**: separate slice — needs to identify HPs from
|
||||
the Summary PDF's heating section.
|
||||
|
||||
Do NOT start HP slices without an explicit go-ahead from the user.
|
||||
|
||||
## Conventions (preserved)
|
||||
|
||||
- **One slice = one commit** — stage by name.
|
||||
- **AAA test convention** — literal `# Arrange / # Act / # Assert`.
|
||||
- **`abs(diff) <= tol`** not `pytest.approx` (strict-pyright clean).
|
||||
- **1e-4 worksheet tolerance** when worksheet is available.
|
||||
- **Spec citation** in commit messages when a slice implements a
|
||||
spec rule (quote RdSAP 10 / SAP 10.2/10.3 page reference).
|
||||
- **Pyright net-zero per file**. Updated baselines:
|
||||
- `datatypes/epc/domain/mapper.py`: 33
|
||||
- `domain/sap10_calculator/worksheet/heat_transmission.py`: 13
|
||||
- `domain/sap10_calculator/rdsap/cert_to_inputs.py`: 35
|
||||
- `datatypes/epc/domain/epc_property_data.py`: 1 (pre-existing)
|
||||
- `domain/sap10_ml/rdsap_uvalues.py`: 1 (pre-existing)
|
||||
|
||||
## Tooling shortcuts (unchanged)
|
||||
|
||||
- EPC fetch: `OPEN_EPC_API_TOKEN` (NOT `EPC_AUTH_TOKEN`) in
|
||||
`backend/.env`.
|
||||
- Worksheet SAP: `pdftotext -layout <worksheet.pdf> -` then grep.
|
||||
- Cascade-component probe: reuse the inline pattern from this
|
||||
handover's "Cascade-component diff" section above.
|
||||
|
||||
## Open items / known gaps from prior session
|
||||
|
||||
- Pre-existing `test_roof_insulated_assumed_with_ni_thickness_uses_
|
||||
50mm_per_section_5_11_4` in `test_heat_transmission.py` fails
|
||||
with `229.99 vs 68.0 ± 2` — verified pre-existing (stash test
|
||||
showed same failure without my changes). Not addressed this
|
||||
session; address separately when the §5.11.4 50mm-rule cascade
|
||||
path is touched.
|
||||
- 8 cohort golden certs (0240, 0300, 0390-2954, 6035, 7536, 8135,
|
||||
2130, 0390-2254) are API-only with integer SAP residual pins —
|
||||
if worksheets become available for any of them, migrate to
|
||||
Layer 4 1e-4 chain pins (cleanest forcing function).
|
||||
|
||||
Good luck. The diagnostic methodology (Summary path → worksheet 1e-4
|
||||
first, then API path catches up) is now proven on 2 boiler certs;
|
||||
cert 9501 should land in ~3-5 slices once the flat-exposure plumbing
|
||||
is in place.
|
||||
Loading…
Add table
Reference in a new issue