diff --git a/docs/sap-spec/NEXT_AGENT_PROMPT.md b/docs/sap-spec/NEXT_AGENT_PROMPT.md index 119d04fc..7edcace0 100644 --- a/docs/sap-spec/NEXT_AGENT_PROMPT.md +++ b/docs/sap-spec/NEXT_AGENT_PROMPT.md @@ -232,126 +232,138 @@ For the new workflow, you'll want a probe that: ## Branch state at handover ``` -$ git log --oneline -8 +$ git log --oneline -10 +31c01a7e Slice 60: thermal bridging y is dwelling-wide, not per-bp +175873b4 Slice 59: heat_transmission apportions window area per bp via window_location +e3dc0b28 Slice 58: secondary fuel cost routes through lodged secondary_fuel_type +a0d9d094 Handover: 4 cert-001479 slices in (54-57); gap at +7.62 SAP; non-fabric next 7a9a8b7e Slice 57: Pre-1950 Elmhurst sloping-ceiling roofs map to thickness=0 07ed871f Slice 56: Elmhurst floor exposed to external air routes through u_exposed_floor c89206fc Slice 55: Elmhurst party-wall code "CU" maps to cavity unfilled 4427b58a Slice 54: Elmhurst mapper sets extensions_count from len(survey.extensions) a756114a Handover: all 6 Elmhurst Summary→SAP chains closed at 1e-4 58088c10 Slice 53: Summary_000487 chain pins SAP at 1e-4 — last cohort cert closed -4ccf9c97 Slice 52: Summary_000477 chain pins SAP at 1e-4; electric shower + decimal RIR rounding -cb4e31a1 Slice 51: Summary_000516 chain pins SAP at 1e-4; roof-window separation ``` -758 cohort + cert-001479 structural tests green; pyright net-zero -(35 baseline) on touched files. +Chain pin `test_summary_001479_full_chain_sap_matches_worksheet_pdf_ +exactly` is committed RED (cascade SAP 70.20 vs worksheet 69.0094, +delta 1.19) as the load-bearing TDD forcing function. All other +chain + golden + heat-transmission tests pass. Pyright net-zero on +touched files. -## Resumption notes for cert 001479 (Slices 54–57 partial progress) +## Resumption notes for cert 001479 (Slices 54–60 in; chain pin RED at delta 1.19) -### What landed -Four mapper slices closed real Elmhurst-side gaps that surfaced when -the cross-mapper diff against the new API counterpart was run for -the first time: +### What landed across two sessions -- **Slice 54** — `extensions_count` now reads `len(survey.extensions)` - instead of the hard-coded `0`. No SAP impact (the cascade iterates - `sap_building_parts`), but a real correctness fix the cross-mapper - parity assertion needs. -- **Slice 55** — Elmhurst party-wall code `"CU"` (Cavity masonry - unfilled) now maps to SAP10 `WALL_CAVITY=4`; `u_party_wall` returns - 0.5 W/m²K matching the worksheet's lodged `Party walls Main … 0.50`. -- **Slice 56** — Floor location `"E To external air"` now routes - through `u_exposed_floor` (Table 20), matching cert 001479 Ext2's - cantilevered exposed timber floor at U=1.20. -- **Slice 57** — PS (Pitched, sloping ceiling) roofs with no lodged - thickness ("As Built") and age band A-D map to `thickness=0`, - giving Table 16 row-0 U=2.30 — matches cert 001479 Ext2's worksheet - `External roof Ext2 … 2.30`. Ext1 (age M) keeps thickness=None - → cascade default 0.15. +**Session 1** (Slices 54-57): fabric mapper gaps from the cross-mapper diff. + +- **Slice 54** — `extensions_count` reads `len(survey.extensions)`. +- **Slice 55** — Elmhurst party-wall code `"CU"` → `WALL_CAVITY=4` + (U=0.5 matching worksheet's `Party walls Main … 0.50`). +- **Slice 56** — Floor location `"E To external air"` routes through + `u_exposed_floor` (Ext2 cantilevered floor at U=1.20). +- **Slice 57** — PS sloping-ceiling roofs at age A-D with "As Built" + thickness map to `thickness=0` → U=2.30 (Ext2 uninsulated roof). + +**Session 2** (Slices 58-60): TDD red-green cycle with the chain pin as +forcing function. Two cascade-level fixes + one mapper fix: + +- **Slice 58** — Secondary fuel cost routing. Mapper derives + `secondary_fuel_type=26` (mains gas) from SAP code 605; cascade + `_fuel_cost` reads `secondary_fuel_type` instead of hardcoding the + electric tariff. Closes a £175/yr ECF distortion ≈ **9 SAP** on + cert 001479. Golden cert 0300-2747 (also mains-gas secondary) + tightens SAP residual −7 → +2 — biggest single golden improvement. +- **Slice 59** — `heat_transmission_from_cert` apportions window + area per `window_location` to each bp's wall deduction (was all-to- + Main). For 001479 Ext1's 6.37 m² window now correctly cuts into + Ext1's wall (U=0.26) instead of Main's (U=0.70). Three golden + certs (6035, 7536, 8135) with non-Main windows tighten all + residuals; cohort certs unaffected (uniform per-bp wall U). +- **Slice 60** — Thermal bridging `y` is dwelling-wide (primary bp's + age band) rather than per-bp. Multi-age dwellings like 001479 + (Main=C, Ext1=M, Ext2=C) and golden 7536 (D, L, F) had Ext1 + bridging under-counted at y=0.08 instead of dwelling's y=0.15. + +**Slice 61 ATTEMPTED + REVERTED**: `SapFloorDimension.floor_lodged_ +u_value` override using Elmhurst Summary §9 "Default U-value". The +override matched 001479's worksheet exactly (Main 0.65, Ext1 0.20, +Ext2 1.20) but broke cohort 000474's 1e-4 pin: that cert's cascade +calibration relied on `u_floor` returning 0.77 for age B + 12.68 m², +while Summary lodges 0.75. The 0.02 U drift × 12.68 m² shifted SAP +beyond 1e-4. **Next session needs a different approach** — either +fix `u_floor` Table 19 cascade for age C (currently 0.60, should be +0.65) without breaking age B, or selectively apply the override. ### Where the chain stands -Mapped Elmhurst cascade for cert 001479: -- Pre-Slice 54: SAP 63.17 vs worksheet 69.0094 (gap +5.84) -- Post-Slice 57: SAP **61.39** vs worksheet 69.0094 (gap **+7.62**) +| Cascade SAP | Delta to 69.0094 | After | +|---|---|---| +| 63.17 | +5.84 | Initial (pre-this-workstream) | +| 61.39 | +7.62 | Post-Slice 57 (fabric only) | +| 70.64 | −1.63 | Post-Slice 58 (secondary fuel) | +| 70.38 | −1.37 | Post-Slice 59 (window apportionment) | +| **70.20** | **−1.19** | **Post-Slice 60 (single-y bridging)** | -Gap widened because each fix was per-data correct; the previous -mapper state was under-counting fabric heat loss in multiple places -that were collectively offsetting some over-counting elsewhere. -Per-bp wall U-values now all match the worksheet exactly: +The chain pin is committed RED at delta 1.19. **Per-bp fabric U-values +all match worksheet exactly** (Main wall 0.70, Ext1 wall 0.26, Ext2 +wall 0.70, etc.). The remaining 1.19 SAP overshoot maps to ~3 W/K of +extra HLC that the cascade is still under-counting: -| BP | Wall | Roof | Party | Floor | -|---|---|---|---|---| -| Main | 0.70 ✓ | 0.14 ✓ | 0.50 ✓ | 0.65 (ground cascade) | -| Ext1 | 0.26 ✓ | 0.15 ✓ | n/a (pwl=0) | 0.20 | -| Ext2 | 0.70 ✓ | **2.30 ✓** | n/a (pwl=0) | **1.20 exposed ✓** | +| Line ref | Cascade | Worksheet | Gap | +|---|---|---|---| +| (29a) walls | 39.77 | 39.77 | ✓ | +| (30) roof | 9.53 | 10.34 | −0.81 (Ext2 sloping-ceiling area) | +| (28a) floor | 21.65 | 23.17 | −1.52 (Main floor U 0.60 vs 0.65) | +| (32) party | 17.07 | 17.07 | ✓ | +| (27) windows | 43.60 | 43.60 | ✓ | +| (26) doors | 5.55 | 5.55 | ✓ | +| (36) bridging | 22.27 | 24.35 | −2.08 (driven by (31) under-count) | +| **(37) total** | **156.62** | **163.84** | **−7.22 W/K** | -Fabric is essentially complete. The remaining ~7.6 SAP gap lives in -non-fabric inputs. +### What likely closes the remaining 1.19 SAP -### What likely drives the remaining 7.6 SAP +1. **`u_floor` Table 19 boundary for age C** (cascade returns 0.60; + worksheet expects 0.65 — same as age B). May be a Table 19 row + boundary miss. Need to read the canonical xlsx Sheet `Table 19` + to confirm correct values. If cascade is wrong, fixing it would + affect cohort but probably in the right direction. +2. **Ext2 roof area for PS sloping ceiling** — cascade uses floor + area (1.92) as roof area; worksheet uses 2.22 (slant length × + width). Factor ≈ 1.156 = sec(30°). Cascade-level: multiply + gross_roof_area by an inclination factor when roof_type starts + with "PS". +3. **`(31)` total external area under-count** of 1.13 m² (drives the + bridging gap). Probably the same Ext2 roof area issue (0.30 m²) + plus other accumulations. Fix #2 likely closes most of this. -- **HLP check**: worksheet `HLP (average) 3.1269`; cascade - total_w_per_k / TFA = 153.15 / 68.51 = **2.235** — cascade is - under-counting total heat loss by ~61 W/K. Combined with cascade - ventilation HLC (~46 W/K) gives total ~199 vs worksheet's expected - ~214 — gap ~15 W/K in non-fabric. -- **Living area fraction**: cascade `0.25`, worksheet `0.28`. The - worksheet computes 17.13/61.18 (Main TFA only?) vs cascade's - 17.13/68.51 (all bp TFA). SAP convention question — may need - cascade-level fix. -- **Internal gains**: cascade `lighting_kwh_per_yr=163` looks low for - 23 fittings; cascade `pumps_fans_kwh_per_yr=160` may differ from - worksheet (which lodges main_heating_category=1). -- **Secondary heating**: cascade has fraction=0.1, η=0.4 (matches - worksheet). SAP code 605 (gas fire flush, sealed-flue) is not wired - through; the cohort 000490 sets `secondary_heating_type` to a SAP - code int — verify cert 001479 needs the same. -- **PCDB boiler index 17507 (Worcester Greenstar 30i)** — cascade - reads `main_heating_efficiency=0.89` (matches worksheet's 89% - winter) so likely already resolved. Confirm. -- **Per-window U vs avg-U routing**: cascade takes per-window U path - (every window has `window_transmission_details`). Worksheet's - windows use 2.80 U (default) — verify cascade matches. - -### Source-data caveats found this session +### Source-data caveats - **Summary PDF vs worksheet age band on Ext1**: Summary §3 says `M 2023 onwards`; worksheet header says `Property Age Band C, Ext1: L, - Ext2: C`. Likely assessor data-entry inconsistency. User decision: - trust the Summary PDF (M); accept whatever residual the worksheet's - L-based calc leaves. Document the caveat in the chain pin docstring - when it lands. -- **Worksheet "0.0" Type column on External Walls**: looks like an - unused column header in Elmhurst's tabular output, not a - shelter-factor input. Cascade ignores it correctly. + Ext2: C`. Trust Summary (mapper does what data says); chain pin + docstring documents the caveat. ### Probe scripts in /tmp (regenerable) -- `/tmp/probe_001479.py` — cross-mapper diff + cascade for both - mappers; baseline for comparing API vs Elmhurst EpcPropertyData. -- `/tmp/sensitivity_001479.py` — single-field patch SAP impact probe; - useful for sequencing slices but stale after each commit (re-run). -- `/tmp/perbp_001479.py` — per-bp cascade U-value dump vs worksheet - expected values; the cleanest "is fabric matching?" check. +- `/tmp/probe_001479.py` — cross-mapper diff + cascade. +- `/tmp/sensitivity_001479.py` — single-field SAP impact probe. +- `/tmp/perbp_001479.py` — per-bp cascade U-value dump vs worksheet. -Cached cert JSON is at `packages/domain/src/domain/sap/rdsap/tests/ -fixtures/golden/0535-9020-6509-0821-6222.json` (token-fetched once, -no further API calls needed). Summary PDF copied into the chain-test -fixtures dir. +Cached cert JSON: `packages/domain/src/domain/sap/rdsap/tests/ +fixtures/golden/0535-9020-6509-0821-6222.json`. Summary PDF in the +chain-test fixtures dir. ### Suggested next steps -1. Probe the cascade's section-by-section line refs (§3 walls, §3 - roofs, §3 windows, §3 thermal bridging, §2 ventilation HLC) against - the worksheet text to find the ~15 W/K HLC gap. -2. Check `living_area_fraction` SAP convention — Main-only vs whole- - dwelling TFA. Cohort certs may have been single-bp so this - convention difference didn't surface. -3. Wire secondary heating SAP code through if a §14 worksheet line ref - shows a different secondary contribution than the cascade. -4. When the chain SAP is within ~0.1 of 69.0094, land the - `test_summary_001479_full_chain_sap_matches_worksheet_pdf_exactly` - pin at 1e-4 — that's the forcing function for the workstream. +1. **`u_floor` Table 19 audit for age C suspended timber** — verify + the cascade matches the canonical RdSAP10 / xlsx. Possible fix + without breaking cohort 000474 (which is age B). +2. **PS sloping-ceiling roof area inclination factor** — multiply + `top_floor_area_m2` by `sec(pitch)` when roof_type is PS. Closes + the (30) and (31) gaps simultaneously. +3. When the chain pin is within ~0.001 of 69.0094, the RED test goes + GREEN — workstream done. Then API ±0.5 pin (test_golden_fixtures + _.py) and cross-parity test are the remaining workstreams. Good luck.