Model/domain/sap10_calculator/docs/HANDOVER_POST_S0380_103.md
Khalim Conn-Kowlessar 7df3fef8bb docs: handover + next-agent prompt post S0380.96..103 (RIR Unknown + §9 floor + MEV PCDB arc + HP-on-E7 cost split)
8 slices shipped this session:
  S0380.96  RIR Unknown insulation       (RdSAP 10 §3.10.1)
  S0380.97  Floor §9 insulation thickness (RdSAP 10 §5.13 Table 20)
  S0380.98  PCDB Table 322 ETL+parser    (PCDF Spec §A.19)
  S0380.99  PCDB Table 329 ETL+parser    (PCDF Spec §A.20)
  S0380.100 MEV SFPav + (230a) helpers   (SAP 10.2 §2.6.4)
  S0380.101 HP SAP code → cat=4 mapper   (SAP 10.2 Table 4a)
  S0380.102 Wire MEV into pumps_fans     (SAP 10.2 Table 4f 230a)
  S0380.103 MEV-fan cost split           (SAP 10.2 Table 12a Grid 2)

Cert 000565 at HEAD `e3abe9b2`:
  sap_score (int)              ✓ EXACT
  pumps_fans_kwh_per_yr        ✓ EXACT (was +2.48 over)
  hot_water_kwh_per_yr         ✓ 0 EXACT
  sap_score_continuous         Δ +0.0182 (SH cascade-driven)
  7 expected fails (was 9)

Next slice candidate: S0380.104 investigate §3-§8 space-heating
cascade -27 kWh under-count (cert-000565-specific; cohort certs
pass at 1e-4). Alternative: S0380.105 CO2 MEV split (mirror of
.103 for Table 12d monthly factors).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 16:13:33 +00:00

16 KiB
Raw Blame History

Handover — post S0380.96..103 (RIR Unknown + §9 floor extractor + MEV PCDB arc + HP-on-E7 cost split)

Branch: feature/per-cert-mapper-validation. HEAD e3abe9b2. Predecessor: HANDOVER_POST_S0380_95.md.

Slices committed this session (S0380.96..103)

Eight spec-cited slices. The first two closed remaining cert 000565 extractor/mapper gaps (RIR "Unknown" insulation + floor §9 "Insulation Thickness"). Slices .98..102 built the MEV PCDB decentralised cascade arc end-to-end (Tables 322 + 329 + SFPav formula + HP-category mapper + wiring). The final slice .103 closed the Table 12a Grid 2 MEV-fan cost split, completing the HP-on-E7 cost cascade.

Slice Commit Spec Cert 000565 outcome
S0380.96 32a4cf20 RdSAP 10 §3.10.1 (PDF p.24) — "Unknown" insulation → Table 18 col 4 age-band default BP[4] FC1 cascade U: 2.30 → 0.15 ✓ EXACT. roof_w_per_k Δ +12.34 → +1.59 (closed -10.75). Continuous SAP Δ -0.44 → -0.20.
S0380.97 7121a86b RdSAP 10 §5.13 Table 20 (PDF p.47) — exposed/semi-exposed floor U by age × thickness BP[2] Ext2 floor U: 0.51 → 0.22 ✓ EXACT. floor_w_per_k ✓ EXACT. sap_score 28 → 29 ✓ EXACT. Continuous SAP Δ -0.0001 (within 1e-4).
S0380.98 b3330821 PCDF Spec Rev 6b §A.19 — PCDB Table 322 Format 427/428 Foundation only. Typed parser + ETL + decentralised_mev_record(pcdb_id) lookup. 48 records ingested. No cascade integration.
S0380.99 433f4a49 PCDF Spec Rev 6b §A.20 — PCDB Table 329 Format 430/432 Foundation only. Typed parser + ETL + mv_in_use_factors_record(system_type). 5 records ingested. No cascade integration.
S0380.100 44fb8c07 SAP 10.2 §2.6.4 equation (1) + Table 4f line (230a) New module worksheet/mev.pymev_sfp_av + mev_decentralised_kwh_per_yr pure helpers. AAA tests pin cert 000565 worksheet values. No cascade integration.
S0380.101 1b183f9c SAP 10.2 Table 4a (PDF p.165) — Heat-pump category 4 HP SAP codes 211-227 / 521-527 → main_heating_category=4 in _elmhurst_main_heating_category (Elmhurst path). Cert 000565 Main 1 (SAP 224) flipped None→4. Transient regression: pumps_fans 255 → 125 (offset bug exposed).
S0380.102 a0413155 SAP 10.2 §2.6.4 + Table 4f (230a) — Wire MEV cascade into _table_4f_additive_components pumps_fans_kwh_per_yr 255 → 252.5159 ✓ EXACT. Schema + extractor + mapper for MV PCDF index / wet rooms / duct type. Elmhurst fan-count convention reverse-engineered from cert 000565 (TODO: validate on a 2nd MEV cert).
S0380.103 e3abe9b2 SAP 10.2 Table 12a Grid 2 (PDF p.191) — FANS_FOR_MECH_VENT blended rate on off-peak MEV-fan cost weighting: 127.5 kWh at 11.6644 p/kWh + 125 kWh at 13.2440 p/kWh → effective 12.4467 p/kWh. cost Δ +£0.39 → -£1.62 (sign flipped; SH cascade residual exposed).

Test baseline at HEAD e3abe9b2: 597 pass + 7 expected 000565 fails (was 585 + 9 at start of session, with .96+.97 closing the sap_score integer fail and .102 closing the pumps_fans fail). The ETL test count grew by ~25 with the new PCDB tables.

Pyright net-zero per touched file across every slice.

Cert 000565 state (HEAD e3abe9b2)

Fabric subtotals

Component Cascade W/K Worksheet W/K Δ Status
walls 601.22 604.07 -2.85 sub-spec
party_walls 65.13 65.13 ✓ EXACT S0380.91
floor 61.67 61.67 ✓ EXACT S0380.97
roof 52.97 51.38 +1.59 residual +1.29 BP[1] formula
windows 9.60 11.48 -1.88 sub-spec
roof_windows 5.02 3.58 +1.44 sub-spec
doors 11.10 11.10 ✓ EXACT full pipeline plumbing
thermal_bridging 129.35 128.65 +0.70 S0380.95
total external area 862.34 857.64 +4.70 S0380.95

SapResult pins (HEAD e3abe9b2)

Pin Cascade Worksheet Δ Status
sap_score (int) 29 29 ✓ EXACT S0380.97
sap_score_continuous 28.5269 28.5087 +0.0182 SH cascade-driven
ecf 5.3850 5.3866 -0.0016 SH cascade-driven
total_fuel_cost_gbp 4678.6372 4680.2593 -1.6221 SH cascade-driven
co2_kg_per_yr 6445.8198 6447.6263 -1.8065 mix: CO2 MEV split + SH
space_heating_kwh_per_yr 58980.8225 59008.3499 -27.5274 §3-§8 cascade gap
main_heating_fuel_kwh_per_yr 34694.6015 34710.7941 -16.1926 downstream of SH
hot_water_kwh_per_yr 3755.0288 3755.0288 ✓ 0 EXACT unchanged
lighting_kwh_per_yr 1387.0237 1384.8353 +2.1884 sub-spec
pumps_fans_kwh_per_yr 252.5159 252.5159 ✓ 0 EXACT S0380.102

Continuous SAP journey across this session

Slice sap_score (int) sap_score_continuous Δ vs ws
Pre-S0380.96 28 28.07 -0.44
S0380.96 28 28.31 -0.20
S0380.97 29 28.5086 -0.0001 (within 1e-4!)
S0380.98..100 29 28.5086 -0.0001 (no cascade change)
S0380.101 29 28.6942 +0.1855 (transient — HP cat=4 only, MEV not yet wired)
S0380.102 29 28.5043 -0.0044 (MEV wired, restored balance)
S0380.103 29 28.5269 +0.0182 (MEV cost split exposed pre-existing SH residual)

Per user direction feedback-spec-floor-skepticism + feedback-spec-floor-skepticism: each slice closed a true spec- correct intermediate-value bug. The continuous-SAP residual is now driven by a §3-§8 SH cascade under-count (main_heating_fuel -16 kWh) that was previously masked by the +£2.01 pumps_fans cost over-count.

Open work — prioritised next slices

S0380.104 — Investigate §3-§8 space-heating cascade -27 kWh

The current biggest residual driver. main_heating_fuel_kwh is -16.19 kWh under ws (34694.60 vs ws 34710.79) → SH cost £1.58 under ws → continuous-SAP +0.0182 OVER ws.

Possible causes:

  1. Heat transmission HLC residual — fabric subtotals net to net ~+29 W/K (post-S0380.95 fabric snapshot). Walls -2.85, roof +1.59, thermal_bridging +0.70, total_external_area +4.70. Roof BP[1] residual formula gap (+1.29 W/K, deferred from S0380.95) is the largest single localised item.
  2. Internal gains — pumps_fans gains contribution changes with HP cat=4 path; verify against ws line (70) by month.
  3. Solar gains / utilization factor — sub-spec window U-values leak into solar gains too.
  4. Mean internal temperature / per-month solve — possible convergence-loop tolerance issue on this multi-BP cert.

Approach: probe per-month space_heat_requirement_kwh vs ws line (98c)m to localise. The cohort certs (000474..000516) hit SH at 1e-4 so the §8 orchestrator IS correct on simpler dwellings — something cert-000565-specific (Detailed-RR + multi-BP + HP + MEV

  • FGHRS + solar HW + draught lobby) is the differentiator.

Expected closure: continuous SAP +0.0182 → within 1e-4.

S0380.105 — CO2 cascade MEV split (Table 12d monthly factors)

Mirror of S0380.103 for CO2. Cert 000565 worksheet line (267):

Pumps, fans and electric keep-hot 252.5159 × 0.1412 = 35.3349

Cascade pumps_fans_co2_factor_kg_per_kwh = 0.14116 (kWh-weighted Table 12d monthly factor for code 30) → 35.6453 kg → +0.31 over ws.

Cause: cascade uses a single Table 12d profile across all pumps_fans kWh. MEV fans have a different MONTHLY DISTRIBUTION than central- heating pumps + flue fans (MEV runs year-round at 0.5 ach; pumps run heating season only). The worksheet integrates separately.

Slice scope: add MevFanEntry-style CO2 helper + new pumps_fans_co2_factor_kg_per_kwh resolution that weights the two streams.

Impact: -0.31 kg/yr → continuous SAP downstream.

S0380.106 — PE cascade MEV split (Table 12e monthly factors)

Mirror of S0380.105 for primary energy. Analogous structure.

S0380.107 — BP[1] residual formula refinement (roof)

BP[1] Ext1 currently has residual +3.68 m² over worksheet (cascade 21.93 vs ws 18.25). The Simplified A_RR formula 12.5 × √(34/1.5) gives 59.51 — minus 37.58 lodged walls = 21.93. Worksheet uses 18.25.

Hypothesis: Ext1's RR height = 3.0 m (not 2.45 m assumed by formula). A height-aware formula like A_RR = perimeter × actual_RR_height might match. Need investigation against multiple Detailed-mode certs with non-2.45 RR heights.

Impact if closed: roof -1.29 W/K (residual drops by 3.68 × 0.35).

S0380.108 — Lighting +2.19 kWh trace residual

Cascade 1387.02 vs ws 1384.84. Sub-spec but breaks 1e-4 strict pin.

§5 Appendix L lighting cascade. Likely a per-cert-lodging gap (bulb count, fixed/non-fixed lighting fraction).

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)

MEV PCDB arc — architecture summary

The S0380.98..103 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) — composer
        reads epc.mechanical_ventilation_index_number, .wet_rooms_count,
              .mechanical_vent_duct_type
        builds Elmhurst per-fan count distribution
        invokes mev.py helpers
    ↓
_table_4f_additive_components(epc) adds the MEV contribution
    ↓
pumps_fans_kwh_per_yr final cascade output

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)
    CalculatorInputs.pumps_fans_fuel_cost_gbp_per_kwh: Optional[float]
    Calculator legacy path uses it via `or other_fuel_cost_gbp_per_kwh`.

Open question for the next agent: the Elmhurst per-fan-count convention in _mev_decentralised_kwh_per_yr_from_cert was reverse- engineered from cert 000565 alone:

  • Each PCDB-defined config (1..6) gets baseline count = 1
  • Through-wall kitchen (5): wet_rooms_count fans total
  • Through-wall other wet (6): wet_rooms_count + 1 fans total

When a 2nd MEV cert lands, validate this. May need to consult Elmhurst's documentation or the BRE-published SAP 10.2 implementation guide.

How to run the baseline

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: 597 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 §3-§8 SH cascade residual + lighting trace + CO2 MEV-split gap.

Files touched this session

File Slices Change
backend/documents_parser/elmhurst_extractor.py .96, .97, .102 "Unknown" insulation token; §9 "Insulation Thickness" cell; §12.1 MV PCDF/Wet-Rooms/Duct-Type fields
backend/documents_parser/tests/test_summary_pdf_mapper_chain.py .96, .97, .101, .103 AAA tests for cert 000565 closures
datatypes/epc/domain/mapper.py .96, .97, .101, .102 _elmhurst_rir_insulation_thickness_mmOptional[int]; floor insulation_thickness_mm plumbing; HP SAP-code → category 4; MV duct-type mapper + PCDF plumbing
datatypes/epc/surveys/elmhurst_site_notes.py .97, .102 FloorDetails.insulation_thickness_mm; VentilationAndCooling.mechanical_ventilation_pcdf_reference + .wet_rooms_count + .duct_type + .approved_installation
domain/sap10_calculator/tables/pcdb/__init__.py .98, .99 decentralised_mev_record + mv_in_use_factors_record lookups
domain/sap10_calculator/tables/pcdb/etl.py .98, .99 Table 322 + 329 typed ETL
domain/sap10_calculator/tables/pcdb/parser.py .98, .99 DecentralisedMevRecord + MvInUseFactorsRecord + parsers
domain/sap10_calculator/tables/pcdb/data/pcdb_table_322_decentralised_mev.jsonl .98 New file — 48 records
domain/sap10_calculator/tables/pcdb/data/pcdb_table_329_mv_in_use_factors.jsonl .99 New file — 5 records
domain/sap10_calculator/worksheet/mev.py .100 New module — mev_sfp_av + mev_decentralised_kwh_per_yr helpers
domain/sap10_calculator/worksheet/tests/test_mev.py .100 AAA tests pinning cert 000565 SFPav
domain/sap10_calculator/rdsap/cert_to_inputs.py .102, .103 _mev_decentralised_kwh_per_yr_from_cert composer; _pumps_fans_fuel_cost_gbp_per_kwh helper
domain/sap10_calculator/calculator.py .103 CalculatorInputs.pumps_fans_fuel_cost_gbp_per_kwh field + legacy cost path
domain/sap10_calculator/tests/test_pcdb_etl.py .98, .99 Added Tables 322, 329 to file list
domain/sap10_calculator/tests/test_pcdb_table_322_lookup.py .98 New file — 3 tests
domain/sap10_calculator/tests/test_pcdb_table_329_lookup.py .99 New file — 4 tests

Spec source quick-reference

  • SAP 10.2 full specification: domain/sap10_calculator/docs/specs/sap-10-2-full-specification-2025-03-14.pdf
    • §2.6.4 (p.16) — Decentralised MEV SFPav equation (1) — S0380.100
    • §5 Table 4a (p.165) — Heat-pump category 4 — S0380.101
    • §5 Table 4f (p.174) — Annual electricity for fans / pumps — S0380.100, .102
    • §5 Table 4g (p.176) — Default SFP for MV systems — S0380.99
    • §10a Table 12a (p.191) — High-rate fractions on off-peak tariffs — S0380.103
  • RdSAP 10 specification: domain/sap10_calculator/docs/specs/RdSAP 10 Specification 10-06-2025.pdf
    • §3.10.1 (p.24) — Unknown insulation → Table 18 default — S0380.96
    • §5.13 + Table 20 (p.47) — Exposed/semi-exposed floor U-values — S0380.97
  • PCDF Spec Rev 6b: domain/sap10_calculator/docs/specs/PCDF_Spec_Rev-06b_12_May_2021.pdf
    • §A.19 Format 427 (Decentralised MEV) — S0380.98
    • §A.20 Format 430 (MV In-Use Factors) — S0380.99
  • 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 — slice-by-slice closure table for .96..103 + open-work analysis
  • MEMORY.md — index entry refreshed at HEAD e3abe9b2

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..103). 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.

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.