mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
docs: handover + next-agent prompt post S0380.105..109 (MEV trifecta + window routing + Connected gable + §5.7/5.8 brick formula)
Captures the 5-slice session that took cert 000565 continuous SAP
from +0.0182 → -0.0059 (magnitude 67% smaller) via spec-cited
intermediate-value closures.
HANDOVER_POST_S0380_109.md full state + per-slice movement
+ per-pin journey + lessons learned
NEXT_AGENT_PROMPT_POST_S0380_109.md focused briefing pointing
at S0380.110 (Lighting g×FF closure
— leading remaining residual at
-2.17 kWh) and S0380.111 (roof
window U formula refinement).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
efb203f7ad
commit
98a4b5b9e6
2 changed files with 567 additions and 0 deletions
323
domain/sap10_calculator/docs/HANDOVER_POST_S0380_109.md
Normal file
323
domain/sap10_calculator/docs/HANDOVER_POST_S0380_109.md
Normal file
|
|
@ -0,0 +1,323 @@
|
|||
# Handover — post S0380.105..109 (MEV CO2/PE + window routing + Connected gable + §5.7/5.8 brick formula)
|
||||
|
||||
Branch: `feature/per-cert-mapper-validation`. **HEAD `efb203f7`**.
|
||||
Predecessor: [`HANDOVER_POST_S0380_103.md`](HANDOVER_POST_S0380_103.md).
|
||||
|
||||
## Slices committed this session (S0380.105..109)
|
||||
|
||||
Five spec-cited slices targeting cert 000565 continuous-SAP closure.
|
||||
The MEV trifecta completed first (.105/.106), then a routing fix
|
||||
(.107) surfaced and re-shaped the fabric residuals, then two
|
||||
spec-correct fabric closures (.108/.109) drove the fabric residual
|
||||
from -0.99 W/K → +0.03 W/K and continuous SAP from +0.0182 → -0.0059
|
||||
(magnitude 67% smaller).
|
||||
|
||||
| Slice | Commit | Spec | Cert 000565 outcome |
|
||||
|---|---|---|---|
|
||||
| **S0380.105** | `8a3aaf7a` | SAP 10.2 Table 12a Grid 2 + Table 12d (PDF p.191, p.194) — MEV CO2 split | `pumps_fans_co2_kg_per_yr` ✓ EXACT (35.3349 vs ws (267)). Total CO2 sign-flipped -1.81 → -2.12 (exposed downstream main_heating CO2 -2.43). |
|
||||
| **S0380.106** | `8effa2d0` | SAP 10.2 Table 12a Grid 2 + Table 12e (p.191, p.195) — MEV PE split | `pumps_fans_pe_kwh_per_yr` ✓ EXACT (383.3797 vs ws (281)). PE 62228.49 → 62227.06. MEV cascade trifecta cost/CO2/PE COMPLETE. |
|
||||
| **S0380.107** | `b7fa5f74` | RdSAP 10 §3.7.1 (PDF p.21) + §8.2 (p.50) — window/rooflight routing | New 4-rule heuristic uses BP roof type alongside glazing/U. Closes windows ✓ EXACT. Net fabric HTC -0.99 → +0.33 W/K. Continuous SAP +0.0182 → -0.0128 (magnitude 30% smaller). Integer SAP TRANSIENTLY 29→28 (crossed 28.5 rounding boundary). S0380.103 cost test reframed to pin rate not total. |
|
||||
| **S0380.108** | `9159e91f` | RdSAP 10 §3.9.2 step (d) + Table 4 row 4 (PDF p.22-23) — Connected RR gables | New `connected_wall` kind: deducts area from A_RR but skips W/K. Closes roof +1.59 → +0.30 W/K (81% closed) + TB +0.71 → +0.15 (79%) + area +4.70 → +1.02 m² (78%). **Integer SAP RECOVERED to 29 ✓ EXACT.** Continuous SAP sign-flipped under (-0.0128 → +0.0293). |
|
||||
| **S0380.109** | `efb203f7` | RdSAP 10 §5.7 Table 13 + §5.8 Table 14 (PDF p.41-42) — solid brick + insulation formula | §5.7+§5.8 chain replaces Table-6 bucket for SOLID_BRICK + lodged thickness + External/Internal insulation. Also adds Table 6 footnote (a) cap on §5.6 stone formula (only when not dry-lined). Walls -1.54 → +0.01 W/K (essentially closed). **Continuous SAP magnitude 80% improved (+0.0293 → -0.0059).** All SH-driven downstream residuals magnitude-reduced 65-80%. |
|
||||
|
||||
**Test baseline at HEAD `efb203f7`:** **608 pass + 7 expected
|
||||
`test_sap_result_pin[000565-*]` fails**. Pyright net-zero per
|
||||
touched file across every slice.
|
||||
|
||||
## Cert 000565 state (HEAD `efb203f7`)
|
||||
|
||||
### Fabric subtotals — essentially closed
|
||||
|
||||
| Component | Cascade W/K | Worksheet W/K | Δ | Status |
|
||||
|---|---:|---:|---:|---|
|
||||
| walls | 604.08 | 604.07 | **+0.01** | sub-spec float drift |
|
||||
| **party_walls** | **65.13** | 65.13 | ✓ EXACT | |
|
||||
| **floor** | **61.67** | 61.67 | ✓ EXACT | |
|
||||
| roof | 51.68 | 51.38 | **+0.30** | sub-spec (S0380.108 closed 81%) |
|
||||
| **windows** | **11.48** | 11.48 | ✓ EXACT | S0380.107 |
|
||||
| roof_windows | 3.15 | 3.58 | -0.43 | cascade U formula gap (see §A below) |
|
||||
| **doors** | **11.10** | 11.10 | ✓ EXACT | |
|
||||
| thermal_bridging | 128.80 | 128.65 | +0.15 | sub-spec (S0380.108 closed 79%) |
|
||||
| total external area | 858.66 | 857.64 | +1.02 | sub-spec (S0380.108 closed 78%) |
|
||||
| **total W/K** | **937.09** | 937.06 | **+0.03** | essentially closed |
|
||||
|
||||
### SapResult pins (HEAD `efb203f7`)
|
||||
|
||||
| Pin | Cascade | Worksheet | Δ | Status |
|
||||
|---|---:|---:|---:|---|
|
||||
| **sap_score (int)** | **29** | 29 | **✓ EXACT** | S0380.108 |
|
||||
| sap_score_continuous | 28.5028 | 28.5087 | -0.0059 | 80% smaller than .104 baseline |
|
||||
| ecf | 5.3874 | 5.3866 | +0.0008 | 50% smaller than .104 |
|
||||
| total_fuel_cost_gbp | 4680.78 | 4680.26 | +0.52 | was -1.62 (.104) / -2.62 (.108) |
|
||||
| co2_kg_per_yr | 6448.34 | 6447.63 | +0.72 | was -1.81 (.104) |
|
||||
| space_heating_kwh_per_yr | 59020.02 | 59008.35 | +11.67 | was -27.5 (.104) |
|
||||
| main_heating_fuel_kwh_per_yr | 34717.66 | 34710.79 | +6.87 | was -16.2 (.104) |
|
||||
| **hot_water_kwh_per_yr** | 3755.03 | 3755.03 | ✓ EXACT | unchanged |
|
||||
| lighting_kwh_per_yr | 1382.67 | 1384.84 | -2.17 | rooflight g×FF default-vs-lodged drift |
|
||||
| **pumps_fans_kwh_per_yr** | **252.5159** | 252.5159 | ✓ EXACT | S0380.102 |
|
||||
| pumps_fans_co2_kg_per_yr | 35.3349 | 35.3349 | ✓ EXACT | S0380.105 |
|
||||
| pumps_fans_pe_kwh_per_yr | 383.3797 | 383.3796 | ✓ EXACT | S0380.106 |
|
||||
|
||||
### Continuous SAP journey
|
||||
|
||||
| Slice | Δ vs ws | Notes |
|
||||
|---|---:|---|
|
||||
| Pre-S0380.105 | +0.0182 | Post-S0380.103 baseline (MEV cost split) |
|
||||
| S0380.105 | +0.0182 | CO2 doesn't feed ECF — no continuous change |
|
||||
| S0380.106 | +0.0182 | PE doesn't feed ECF either |
|
||||
| S0380.107 | **-0.0128** | Window routing fix; 30% magnitude reduction; integer SAP transiently 28 |
|
||||
| S0380.108 | **+0.0293** | Connected gable deduction; integer SAP back to 29; sign-flipped |
|
||||
| S0380.109 | **-0.0059** | Solid brick §5.7+§5.8; 80% magnitude reduction from .108 |
|
||||
|
||||
**Magnitude trajectory:** 0.0182 → 0.0128 → 0.0293 → **0.0059**.
|
||||
Net 67% improvement from session start.
|
||||
|
||||
## Open work — prioritised next slices
|
||||
|
||||
### S0380.110 — Lighting rooflight g×FF default-vs-lodged drift (low-medium leverage)
|
||||
|
||||
**Current residual:** -2.17 kWh/yr (cascade UNDER ws). After S0380.107
|
||||
windows correctly route to sap_roof_windows, the cascade applies the
|
||||
Appendix L L2a daylight factor formula with rooflight contribution
|
||||
using `_G_LIGHT_DEFAULT = 0.80` and `_FRAME_FACTOR_DEFAULT = 0.70`
|
||||
regardless of the lodged glazing/frame on each rooflight.
|
||||
|
||||
For cert 000565:
|
||||
- Item 2 (Ext2 NR rooflight, 1.2 m², Triple glazing PVC frame):
|
||||
actual g×FF = 0.70 × 0.70 = 0.49 (cascade uses 0.56)
|
||||
- Item 5 (Ext4 A rooflight, 0.5 m², Double glazing Wood frame):
|
||||
actual g×FF = 0.80 × 0.70 = 0.56 (cascade uses 0.56 ✓)
|
||||
|
||||
Area-weighted: cascade overstates G_L by ~0.052 × 1.7 m² → DF
|
||||
slightly too low → lighting kWh slightly low.
|
||||
|
||||
**Spec:** SAP 10.2 Appendix L L2a (PDF p.~74) — G_L numerator should
|
||||
use each window's own g_perpendicular and frame_factor, not defaults.
|
||||
|
||||
**Fix location:** `domain/sap10_calculator/worksheet/internal_gains.py`
|
||||
function `_daylight_factor_from_cert`, the `rooflight_g_l_numerator`
|
||||
computation around line 613-618 — iterate `epc.sap_roof_windows` and
|
||||
use each one's actual `g_perpendicular` + `frame_factor` instead of
|
||||
defaults.
|
||||
|
||||
**Expected closure:** lighting -2.17 → ~0 kWh/yr. Tiny continuous-SAP
|
||||
ripple (lighting feeds CO2/cost/PE via the Table 12 monthly factors).
|
||||
|
||||
### S0380.111 — Roof window U formula refinement (low leverage)
|
||||
|
||||
**Current residual:** -0.43 W/K (cascade UNDER ws). Cascade computes
|
||||
roof window effective U via `1 / (1/U_raw + 0.04)` = 1.852 for U_raw =
|
||||
2.0. Worksheet uses U_eff = 2.1062 for the same raw U.
|
||||
|
||||
Reverse-engineered: 1/2.1062 = 0.4748; 0.5 (=1/U_raw) - 0.4748 =
|
||||
0.0252 — so the spec correction for roof windows differs from the
|
||||
vertical-window +0.04 by a factor of −0.0648.
|
||||
|
||||
**Spec hunt:** SAP 10.2 §3.2 / Table 6c (PDF p.51). Table 6c has a
|
||||
distinct "U-value** (roof window)" column with values higher than the
|
||||
vertical-glazing column (by typically ~+0.2-0.3 W/m²K). The exact
|
||||
correction depends on the spec's definition of roof-window surface
|
||||
resistances vs vertical-window film coefficients.
|
||||
|
||||
**Likely fix:** in `heat_transmission.py` the roof-window effective U
|
||||
should use a lookup keyed on the lodged glazing type rather than a
|
||||
flat +0.04 correction (which is the SAP10.2 §3.2 "windows" formula,
|
||||
not the rooflight one).
|
||||
|
||||
**Expected closure:** roof_windows -0.43 → 0 W/K. HTC change +0.43
|
||||
W/K → continuous SAP -0.0015 (cascade more under). The roof_windows
|
||||
closure makes the residual SHIFT in the same direction as current
|
||||
-0.0059, so net continuous SAP slightly worse before lighting closes.
|
||||
|
||||
### S0380.112 — Walls precision +0.01 W/K (sub-spec)
|
||||
|
||||
Tiny float rounding artifact in BP[0] alt_wall_1 (granite + dry-line):
|
||||
cascade computes raw U=2.3405, ws displays U=2.34, A×U product diff is
|
||||
0.01 W/K. Rounding to 2 d.p. in the §5.6 dry-line path was added in
|
||||
S0380.109 — verify it fires for this case.
|
||||
|
||||
### Deferred (unchanged from earlier handovers)
|
||||
|
||||
- 12 gas-combi PV certs at +0.5..+1.6 PE (no worksheets)
|
||||
- 5 SAP-residual API-only certs (no worksheets)
|
||||
|
||||
## What this session learned
|
||||
|
||||
### Pattern: spec-correct intermediate fixes can sign-flip end-result residuals
|
||||
|
||||
Each of S0380.107, .108, .109 shifted end-result residuals (cost,
|
||||
CO2, SH, continuous SAP) by amounts larger than the closure itself —
|
||||
because the cascade's pre-slice residuals were partially CANCELLING.
|
||||
Removing one mis-handled component exposes other residuals that were
|
||||
masked.
|
||||
|
||||
The user's stated philosophy makes this explicit:
|
||||
> "It's okay if we temp drift away from continuous SAP, as long as we
|
||||
> are actually fixing true problems with the intermediate values.
|
||||
> Eventually, I expect the error of continuous SAP to be zero but
|
||||
> that is only possible if we fix all of the sub components and
|
||||
> remain true to spec."
|
||||
|
||||
The trajectory bears this out: 5 slices → continuous SAP magnitude
|
||||
0.0182 → 0.0059 (67% improvement) through multiple sign-flips along
|
||||
the way.
|
||||
|
||||
### Pattern: existing snapshot tests need updating when they pin downstream metrics
|
||||
|
||||
S0380.103 cost test (`test_summary_000565_mev_fans_cost_uses_table_
|
||||
12a_grid_2_fans_for_mech_vent_rate`) was originally written against
|
||||
`total_fuel_cost_gbp` with a tight `< +£0.05` threshold. After
|
||||
S0380.107 broke that threshold (cascade catches up on fabric HTC and
|
||||
total cost shifts by £2+), the test was reframed to pin
|
||||
`inputs.pumps_fans_fuel_cost_gbp_per_kwh` directly — the specific
|
||||
metric S0380.103 closes, decoupled from downstream changes.
|
||||
|
||||
Similarly, golden cert 6035 PE/CO2 pins were updated in S0380.109 per
|
||||
[[feedback-golden-residuals-near-zero]] — the cascade got closer to
|
||||
the actual EPC value, which is the intended direction.
|
||||
|
||||
When future slices fire on a cert that's pinned with downstream
|
||||
metrics, the same pattern applies: update the pin or reframe to a
|
||||
narrower intermediate.
|
||||
|
||||
## MEV PCDB arc — architecture summary (unchanged from .103 handover)
|
||||
|
||||
The S0380.98..106 arc landed the entire MEV decentralised cascade
|
||||
end-to-end. Architecture in dependency order:
|
||||
|
||||
```
|
||||
PCDB pcdb10.dat
|
||||
↓ ETL (etl.py, parser.py)
|
||||
Table 322 (per-fan SFP) ←→ Table 329 (per-ducting IUF)
|
||||
↓ runtime lookups (__init__.py)
|
||||
decentralised_mev_record(pcdb_id) + mv_in_use_factors_record(system_type)
|
||||
↓
|
||||
worksheet/mev.py — pure helpers
|
||||
mev_sfp_av(fan_entries) → §2.6.4 equation (1) avg SFP
|
||||
mev_decentralised_kwh_per_yr(sfp_av, V) → Table 4f line (230a) kWh
|
||||
↓
|
||||
cert_to_inputs.py
|
||||
_mev_decentralised_kwh_per_yr_from_cert(epc)
|
||||
reads epc.mechanical_ventilation_index_number, .wet_rooms_count,
|
||||
.mechanical_vent_duct_type
|
||||
invokes mev.py helpers
|
||||
↓
|
||||
_table_4f_additive_components(epc) adds MEV → pumps_fans_kwh_per_yr
|
||||
|
||||
For COST (S0380.103):
|
||||
_pumps_fans_fuel_cost_gbp_per_kwh(tariff, mev_kwh, total_pumps_fans_kwh)
|
||||
→ kWh-weighted blended rate (FANS_FOR_MECH_VENT vs ALL_OTHER_USES)
|
||||
|
||||
For CO2 (S0380.105):
|
||||
_pumps_fans_co2_factor_kg_per_kwh(tariff, mev_kwh, total_pumps_fans_kwh, monthly)
|
||||
→ kWh-weighted blend of FANS_FOR_MECH_VENT + ALL_OTHER_USES Table 12d factors
|
||||
|
||||
For PE (S0380.106):
|
||||
_pumps_fans_primary_factor(tariff, mev_kwh, total_pumps_fans_kwh, monthly)
|
||||
→ kWh-weighted blend of FANS_FOR_MECH_VENT + ALL_OTHER_USES Table 12e factors
|
||||
```
|
||||
|
||||
All three helpers fall back to the existing ALL_OTHER_USES rate on
|
||||
STANDARD-tariff certs and no-MEV certs (cohort-safe). The MEV
|
||||
cascade trifecta is now COMPLETE for cert 000565.
|
||||
|
||||
## How to run the baseline
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/workspaces/model python -m pytest \
|
||||
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \
|
||||
backend/documents_parser/tests/test_elmhurst_extractor.py \
|
||||
backend/documents_parser/tests/test_elmhurst_end_to_end.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_mev.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \
|
||||
domain/sap10_calculator/tests/test_pcdb_table_322_lookup.py \
|
||||
domain/sap10_calculator/tests/test_pcdb_table_329_lookup.py \
|
||||
--no-cov -q
|
||||
```
|
||||
|
||||
Expected: **608 pass + 7 expected `test_sap_result_pin[000565-*]`
|
||||
fails**.
|
||||
|
||||
The 7 expected fails (verbatim):
|
||||
```
|
||||
sap_score_continuous
|
||||
ecf
|
||||
total_fuel_cost_gbp
|
||||
co2_kg_per_yr
|
||||
space_heating_kwh_per_yr
|
||||
main_heating_fuel_kwh_per_yr
|
||||
lighting_kwh_per_yr
|
||||
```
|
||||
|
||||
All driven by the residual lighting -2.17 kWh + roof window U formula
|
||||
gap -0.43 W/K + sub-spec walls float drift +0.01 W/K. The first two
|
||||
are the open S0380.110 / S0380.111 work fronts.
|
||||
|
||||
## Files touched this session
|
||||
|
||||
| File | Slices | Change |
|
||||
|---|---|---|
|
||||
| `domain/sap10_calculator/rdsap/cert_to_inputs.py` | .105, .106 | `_pumps_fans_co2_factor_kg_per_kwh` + `_pumps_fans_primary_factor` helpers + wire into call sites |
|
||||
| `datatypes/epc/domain/mapper.py` | .107, .108 | Survey-aware `_is_elmhurst_roof_window` predicate; `_elmhurst_bp_roof_type` helper; Connected-gable routing to new `connected_wall` kind |
|
||||
| `domain/sap10_calculator/worksheet/heat_transmission.py` | .108, .109 | `connected_wall` branch (deducts area, no W/K); pass `wall_thickness_mm` to per-BP main wall `u_wall` |
|
||||
| `domain/sap10_ml/rdsap_uvalues.py` | .109 | `_u_brick_thin_wall_age_a_to_e` (§5.7 Table 13); `_r_insulation_table_14` (§5.8 Table 14 interpolation); §5.7+§5.8 branch in `u_wall`; Table 6 footnote (a) cap on §5.6 stone (only when not dry-lined); 2 d.p. rounding on §5.6 dry-line result |
|
||||
| `domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py` | .109 | Re-pin cert 6035 PE/CO2 expectations |
|
||||
| `backend/documents_parser/tests/test_summary_pdf_mapper_chain.py` | .105, .106, .107, .108, .109 | AAA tests for each slice; S0380.103 test reframed to pin cost rate directly |
|
||||
|
||||
## Spec source quick-reference
|
||||
|
||||
- **SAP 10.2 full specification**: `domain/sap10_calculator/docs/specs/sap-10-2-full-specification-2025-03-14.pdf`
|
||||
- §3.2 / Table 6c (p.51) — Window/rooflight U formula — S0380.111 target
|
||||
- §10a Table 12a Grid 2 (p.191) — Other electricity uses high-rate fraction — S0380.105, .106
|
||||
- §10b Table 12d (p.194) — Monthly CO2 factors — S0380.105
|
||||
- §10c Table 12e (p.195) — Monthly PE factors — S0380.106
|
||||
- Appendix L L2a (p.~74) — Daylight factor G_L — S0380.110 target
|
||||
- **RdSAP 10 specification**: `domain/sap10_calculator/docs/specs/RdSAP 10 Specification 10-06-2025.pdf`
|
||||
- §3.7.1 (p.21) — Window vs roof window classification — S0380.107
|
||||
- §3.9.2 step (d) (p.23) — Connected gable area deduction — S0380.108
|
||||
- §5.6 (p.40) + Table 12 (p.41) — Stone wall thin-wall formula — S0380.109 (cap)
|
||||
- §5.7 (p.41) + Table 13 (p.41) — Brick wall U₀ by thickness — S0380.109
|
||||
- §5.8 (p.41-42) + Table 14 (p.42) — Insulation R formula — S0380.109
|
||||
- §8.2 (p.50) — Glazed walls/roof routing — S0380.107
|
||||
- Table 4 row 4 (p.22) — Connected gable U=0 — S0380.108
|
||||
- Table 6 footnote (a) (p.34) — §5.6 formula cap — S0380.109
|
||||
- **SAP 10.3 at** `sap-10-3-full-specification-2026-01-13.pdf`: **DO NOT reference** ([[feedback-sap-10-2-only-never-10-3]])
|
||||
|
||||
## Memory updated this session
|
||||
|
||||
- `project_cert_000565_recovery_state` — appended .105/.106/.107/.108/.109 closures + open-work analysis
|
||||
- `MEMORY.md` — refreshed at HEAD `efb203f7`
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't reference SAP 10.3** ([[feedback-sap-10-2-only-never-10-3]]).
|
||||
- **Don't widen pin tolerances or xfail residual gaps**
|
||||
([[feedback-zero-error-strict]]). The 7 cert 000565 fails are the
|
||||
work queue. When a slice surfaces a downstream pin that drifts (e.g.
|
||||
the integer SAP rounding flip in S0380.107), bring it back via a
|
||||
complementary closure in a subsequent slice (S0380.108 pattern).
|
||||
- **Don't re-investigate any closed work** (.91..109). All settled.
|
||||
- **Don't add new helpers to `domain/sap10_ml/`** — deprecation path
|
||||
per [[project-sap10_ml-deprecation]]. New cascade helpers belong
|
||||
under `domain/sap10_calculator/`. (S0380.109 extended existing
|
||||
helpers in `rdsap_uvalues.py` — acceptable since the file is the
|
||||
current authoritative wall-U-value table and a migration plan
|
||||
hasn't yet landed for it specifically.)
|
||||
- **Don't avoid spec-correct closures because continuous SAP drifts
|
||||
away or sign-flips** — user explicitly OK'd transient drift. Zero
|
||||
error achievable only when every component is spec-correct.
|
||||
- **Don't pin downstream-only metrics with tight thresholds** —
|
||||
S0380.103 cost test pattern. Pin the narrowest intermediate the
|
||||
slice changes.
|
||||
|
||||
## Memory hygiene
|
||||
|
||||
After the next slice, update:
|
||||
- `project_cert_000565_recovery_state` — append slice closure +
|
||||
refresh the open work-items table
|
||||
- `MEMORY.md` — refresh HEAD + one-line summary
|
||||
|
||||
Good luck.
|
||||
244
domain/sap10_calculator/docs/NEXT_AGENT_PROMPT_POST_S0380_109.md
Normal file
244
domain/sap10_calculator/docs/NEXT_AGENT_PROMPT_POST_S0380_109.md
Normal file
|
|
@ -0,0 +1,244 @@
|
|||
# Next-agent prompt — post S0380.105..109
|
||||
|
||||
Branch: `feature/per-cert-mapper-validation`.
|
||||
HEAD: `efb203f7`.
|
||||
|
||||
Read these in order before any tool call:
|
||||
|
||||
1. [`HANDOVER_POST_S0380_109.md`](HANDOVER_POST_S0380_109.md) — full state
|
||||
2. [`HANDOVER_POST_S0380_103.md`](HANDOVER_POST_S0380_103.md) — predecessor (background)
|
||||
|
||||
Also load these memories before starting:
|
||||
|
||||
- `project_cert_000565_recovery_state` — per-slice history + per-pin state
|
||||
- `reference_unmapped_sap_code` — calculator strict-raise pattern
|
||||
- `project_sap10_ml_deprecation` — `domain/sap10_ml/` is on the
|
||||
deprecation path; new cascade helpers should land under
|
||||
`domain/sap10_calculator/`
|
||||
- `feedback_sap_10_2_only_never_10_3` — **CRITICAL** — never reference
|
||||
SAP 10.3 spec
|
||||
- `feedback_spec_citation_in_commits` — quote spec text + page in
|
||||
commit messages
|
||||
- `feedback_verify_handover_claims` — verify spec citations + numeric
|
||||
claims before implementing the prescribed fix
|
||||
- `feedback_zero_error_strict` — pyright net-zero per touched file
|
||||
- `feedback_commit_per_slice` — one slice = one commit
|
||||
- `feedback_aaa_test_convention` — every new test uses literal
|
||||
`# Arrange / # Act / # Assert` headers
|
||||
- `feedback_e2e_validation_philosophy` — component pins at <1e-3;
|
||||
SAP integer delta=0; no adaptive ceilings
|
||||
- `feedback_abs_diff_over_pytest_approx` — use `abs(x - y) <= tol`
|
||||
instead of `pytest.approx` to keep pyright net-zero
|
||||
- `feedback_spec_floor_skepticism` — skeptical of "spec-precision
|
||||
floor" claims; verify the spec citation against the PDF first
|
||||
- `feedback_golden_residuals_near_zero` — golden pins should be
|
||||
re-pinned closer to zero as the cascade improves
|
||||
|
||||
## Critical user direction
|
||||
|
||||
The user's **primary metric is `sap_score_continuous`** (not just
|
||||
integer `sap_score`). The user has explicitly stated:
|
||||
|
||||
> "It's okay if we temp drift away from continuous SAP, as long as we
|
||||
> are actually fixing true problems with the intermediate values.
|
||||
> Eventually, I expect the error of continuous SAP to be zero but
|
||||
> that is only possible if we fix all of the sub components and
|
||||
> remain true to spec."
|
||||
|
||||
And:
|
||||
|
||||
> "We should aim to get SAP continue exact, along with all sections.
|
||||
> But we'll see."
|
||||
|
||||
**Implication:** ship spec-correct slices even when they cause
|
||||
transient continuous-SAP drift. Sign-flips are expected and OK —
|
||||
they mean a previously-cancelling residual is now exposed.
|
||||
|
||||
## State summary
|
||||
|
||||
This session shipped **S0380.105..109** — five spec-cited slices.
|
||||
Trifecta-complete on MEV cascade (cost/CO2/PE), then three fabric
|
||||
closures that moved continuous SAP from +0.0182 → -0.0059 (magnitude
|
||||
67% smaller).
|
||||
|
||||
1. **S0380.105** (`8a3aaf7a`) — MEV CO2 split via Table 12a Grid 2 +
|
||||
Table 12d. `pumps_fans_co2` ✓ EXACT.
|
||||
2. **S0380.106** (`8effa2d0`) — MEV PE split via Table 12a Grid 2 +
|
||||
Table 12e. `pumps_fans_pe` ✓ EXACT. MEV trifecta COMPLETE.
|
||||
3. **S0380.107** (`b7fa5f74`) — Window/rooflight routing via BP roof
|
||||
type (RdSAP 10 §3.7.1 + §8.2). Windows ✓ EXACT. Net fabric HTC
|
||||
-0.99 → +0.33 W/K. Continuous SAP +0.0182 → -0.0128. Integer SAP
|
||||
transiently 28 (rounding boundary).
|
||||
4. **S0380.108** (`9159e91f`) — Connected RR gables deduct from A_RR
|
||||
(RdSAP 10 §3.9.2 step d + Table 4 row 4). Roof/TB/area all closed
|
||||
~80%. **Integer SAP recovered to 29 ✓ EXACT.** Continuous SAP
|
||||
sign-flipped to +0.0293.
|
||||
5. **S0380.109** (`efb203f7`) — Solid brick + insulation via §5.7
|
||||
Table 13 + §5.8 Table 14. Walls -1.54 → +0.01 W/K (essentially
|
||||
closed). **Continuous SAP magnitude 80% improved (+0.0293 →
|
||||
-0.0059).** All SH-downstream residuals magnitude-reduced 65-80%.
|
||||
|
||||
**Cert 000565 state at HEAD `efb203f7`:**
|
||||
|
||||
| Pin | Cascade | Worksheet | Δ |
|
||||
|---|---:|---:|---:|
|
||||
| **sap_score (int)** | **29** | 29 | **✓ EXACT** |
|
||||
| sap_score_continuous | 28.5028 | 28.5087 | -0.0059 |
|
||||
| ecf | 5.3874 | 5.3866 | +0.0008 |
|
||||
| total_fuel_cost_gbp | 4680.78 | 4680.26 | +0.52 |
|
||||
| co2_kg_per_yr | 6448.34 | 6447.63 | +0.72 |
|
||||
| space_heating_kwh_per_yr | 59020.02 | 59008.35 | +11.67 |
|
||||
| main_heating_fuel_kwh_per_yr | 34717.66 | 34710.79 | +6.87 |
|
||||
| **pumps_fans_kwh_per_yr** | **252.5159** | 252.5159 | **✓ 0 EXACT** |
|
||||
| **hot_water_kwh_per_yr** | 3755.0288 | 3755.0288 | ✓ 0 EXACT |
|
||||
| lighting_kwh_per_yr | 1382.6657 | 1384.8353 | -2.17 |
|
||||
|
||||
**Fabric (cascade vs ws):**
|
||||
|
||||
| Component | Δ W/K |
|
||||
|---|---:|
|
||||
| walls | +0.01 (sub-spec float drift) |
|
||||
| roof | +0.30 |
|
||||
| windows | ✓ 0 EXACT |
|
||||
| roof_windows | -0.43 (cascade U formula gap) |
|
||||
| TB | +0.15 |
|
||||
| **total** | **+0.03** (essentially closed) |
|
||||
|
||||
## Recommended next slice — S0380.110 § Lighting rooflight g×FF default-vs-lodged drift
|
||||
|
||||
**Current residual:** -2.17 kWh/yr (cascade UNDER ws lighting).
|
||||
|
||||
### Why it's now the leading residual
|
||||
|
||||
After S0380.107 windows correctly route to sap_roof_windows, the
|
||||
cascade applies the Appendix L L2a daylight factor formula with
|
||||
rooflight contribution using `_G_LIGHT_DEFAULT = 0.80` and
|
||||
`_FRAME_FACTOR_DEFAULT = 0.70` regardless of the lodged glazing/frame
|
||||
on each rooflight (`domain/sap10_calculator/worksheet/internal_gains.py`
|
||||
function `_daylight_factor_from_cert` at lines ~613-618).
|
||||
|
||||
For cert 000565:
|
||||
- Item 2 (Ext2 rooflight, 1.2 m², Triple PVC): actual g×FF = 0.70 × 0.70 = 0.49 (cascade uses 0.56)
|
||||
- Item 5 (Ext4 rooflight, 0.5 m², Double Wood): actual g×FF = 0.80 × 0.70 = 0.56 (cascade uses 0.56 ✓)
|
||||
|
||||
Area-weighted cascade OVERSTATES rooflight G_L contribution by
|
||||
~0.052 × 1.7 m² → DF too low → cascade lighting kWh too low.
|
||||
|
||||
### Spec citation target
|
||||
|
||||
SAP 10.2 Appendix L §L2a (PDF p.~74) — the G_L numerator formula sums
|
||||
over each window with its OWN glazing-type g_perpendicular and frame
|
||||
factor, not a fixed default. Verify by reading the L2a / Table 6d
|
||||
section before implementing.
|
||||
|
||||
### Investigation approach
|
||||
|
||||
1. Confirm the L2a spec formula uses per-window g and FF.
|
||||
2. Probe the cascade vs worksheet for cert 000565 daylight factor:
|
||||
```python
|
||||
from domain.sap10_calculator.worksheet.tests._elmhurst_worksheet_000565 import build_epc
|
||||
from domain.sap10_calculator.worksheet.internal_gains import _daylight_factor_from_cert, OvershadingCategory
|
||||
from domain.sap10_calculator.rdsap.cert_to_inputs import _rooflight_total_area_m2_from_cert
|
||||
epc = build_epc()
|
||||
rooflight_area = _rooflight_total_area_m2_from_cert(epc)
|
||||
df = _daylight_factor_from_cert(epc, OvershadingCategory.AVERAGE, rooflight_area)
|
||||
# cascade df ~ 1.34; ws implied df from continuous E_L ~ 1.34 + small delta
|
||||
```
|
||||
3. Change `_daylight_factor_from_cert` to iterate `epc.sap_roof_windows`
|
||||
for the rooflight numerator, summing `area × g_perpendicular ×
|
||||
frame_factor × 1.0` (Z_L = 1.0 for rooflights per Table 6d note 2).
|
||||
4. Sanity-check cohort: cohort certs that have rooflights (e.g. 000516
|
||||
W6) lodge similar g/FF as the current defaults → minimal cohort
|
||||
change.
|
||||
|
||||
### Expected closure
|
||||
|
||||
- lighting_kwh_per_yr -2.17 → ~0 kWh/yr
|
||||
- continuous SAP -0.0059 → small change (lighting feeds CO2/cost/PE
|
||||
via Table 12 monthly factors)
|
||||
|
||||
## Alternative next slice — S0380.111 § Roof window U formula refinement
|
||||
|
||||
**Current residual:** -0.43 W/K (cascade UNDER ws on roof_windows).
|
||||
|
||||
Cascade computes roof window effective U via `1 / (1/U_raw + 0.04)` =
|
||||
1.852 for U_raw = 2.0. Worksheet uses U_eff = 2.1062 for the same raw
|
||||
U. The cascade's vertical-window formula doesn't apply to rooflights
|
||||
— SAP 10.2 Table 6c has a distinct "U-value (roof window)" column.
|
||||
|
||||
**Spec hunt:** SAP 10.2 §3.2 / Table 6c (PDF p.51) — has separate
|
||||
"U-value** (roof window)" column. The note says "Roof pitch 45°
|
||||
(unless horizontal), wooden or PVC". The Table 6c values for the
|
||||
glazing types lodged on cert 000565 rooflights (Double 2002-2021
|
||||
@ U=2.0 raw, Triple 2002-2021 @ U=2.0 raw) should give U_eff = 2.11.
|
||||
|
||||
**Fix location:** `domain/sap10_calculator/worksheet/heat_transmission.py`
|
||||
roof window U computation — should use Table 6c roof-window column
|
||||
keyed on glazing type rather than the +0.04 vertical-window formula.
|
||||
|
||||
**Lower leverage** than S0380.110 — closes -0.43 W/K HTC →
|
||||
~-0.0015 continuous SAP shift. The roof_windows closure makes the
|
||||
residual SHIFT in the same direction as current -0.0059, so net
|
||||
continuous SAP slightly worse before S0380.110 lighting closes.
|
||||
|
||||
## Standard workflow per slice
|
||||
|
||||
1. Read SAP 10.2 / RdSAP 10 spec page for the change — quote it in commit
|
||||
2. Probe current cascade output; identify exact spec-vs-cascade gap
|
||||
3. Write failing test FIRST (AAA structure)
|
||||
4. Implement helper / change
|
||||
5. Verify test passes
|
||||
6. Run full handover suite (command below)
|
||||
7. Check pyright on touched files — net-zero from baseline
|
||||
(use `git stash` + re-run pyright to compute baseline)
|
||||
8. Commit with spec citation + verbatim quote
|
||||
9. Update relevant memory if state changed
|
||||
|
||||
## How to run the baseline
|
||||
|
||||
```bash
|
||||
PYTHONPATH=/workspaces/model python -m pytest \
|
||||
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \
|
||||
backend/documents_parser/tests/test_elmhurst_extractor.py \
|
||||
backend/documents_parser/tests/test_elmhurst_end_to_end.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_appendix_h_solar.py \
|
||||
domain/sap10_calculator/worksheet/tests/test_mev.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py \
|
||||
domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \
|
||||
domain/sap10_calculator/tests/test_pcdb_table_322_lookup.py \
|
||||
domain/sap10_calculator/tests/test_pcdb_table_329_lookup.py \
|
||||
--no-cov -q
|
||||
```
|
||||
|
||||
Expected: **608 pass + 7 expected `test_sap_result_pin[000565-*]`
|
||||
fails**.
|
||||
|
||||
After S0380.110 the lighting pin should close to ✓ EXACT (6 expected
|
||||
fails). After both .110 and .111, the remaining sub-spec residuals
|
||||
should be in a closure-ready state for the final continuous-SAP push.
|
||||
|
||||
## What NOT to do
|
||||
|
||||
- **Don't reference SAP 10.3** ([[feedback-sap-10-2-only-never-10-3]]).
|
||||
- **Don't widen pin tolerances or xfail residual gaps**
|
||||
([[feedback-zero-error-strict]]). The 7 cert 000565 fails are the
|
||||
work queue.
|
||||
- **Don't re-investigate any closed work** (.91..109). All settled.
|
||||
- **Don't add new helpers to `domain/sap10_ml/`** — deprecation path
|
||||
per [[project-sap10_ml-deprecation]]. New cascade helpers belong
|
||||
under `domain/sap10_calculator/`.
|
||||
- **Don't avoid spec-correct closures because continuous SAP drifts
|
||||
away** — user explicitly OK'd transient drift. Zero error
|
||||
achievable only when every component is spec-correct.
|
||||
- **Don't pin downstream-only metrics with tight thresholds** — pin
|
||||
the narrowest intermediate the slice changes.
|
||||
|
||||
## Memory hygiene
|
||||
|
||||
After the next slice, update:
|
||||
- `project_cert_000565_recovery_state` — append closure + open work-
|
||||
items refresh
|
||||
- `MEMORY.md` index — refresh HEAD + one-line summary
|
||||
|
||||
Good luck.
|
||||
Loading…
Add table
Reference in a new issue