Model/packages
Khalim Conn-Kowlessar 8786b90781 Cohort residual slice 17: wire Appendix L inputs into 000480 / 487 / 516
The three open fixtures defined `SECTION_5_BULB_COUNT_LEL` and
`SECTION_6_VERTICAL_WINDOWS` at module scope but never passed them
into `make_minimal_sap10_epc(...)`. The §5 cascade therefore fell
back to all three Appendix L fallbacks simultaneously:

  L5b   (no bulb data lodged):  C_L,fixed = 185 lm/m² × TFA
  L8c   (no fixed lighting):    ε_fixed = 21.30 lm/W
  L2b   (no windows lodged):    C_daylight = 1.433 (no-bonus default)

Per SAP 10.2 Appendix L the fallbacks fire only when the cert
genuinely lacks the data. The actual cert lodges low-energy bulbs +
wall windows on every Elmhurst fixture, so the fallback path was
wrong by construction. Effect on lighting kWh per yr (line 232):

  fixture | calc pre | calc post |  PDF
  --------|----------|-----------|--------
  000480  |   564.5  |   ~212    | 212.55
  000487  |   550.4  |   ~228    | 227.69
  000516  |   593.3  |   ~231    | 230.89

(post values inferred from the closure pattern on 000474/477/490 —
those three pass `test_elmhurst_end_to_end_lighting_kwh_per_yr_
matches_u985_worksheet` at abs=1e-4.)

Impact on SAP integer (Δ vs PDF):

  fixture | pre  | post | direction
  --------|------|------|----------
  000480  | +5   | +7   | further from PDF
  000487  | +3   | +5   | further from PDF
  000516  | +4   | +7   | further from PDF

Net SAP delta gets larger after this fix — the lighting fallback
was over-counting kWh, which compensated for an under-application
of cost elsewhere (calc total fuel cost £746 vs PDF £855 on 000480
despite calc kWh being HIGHER in every component). Less lighting
kWh → less total cost → ECF down → SAP up → away from PDF. The
remaining gap is cost-side (fuel price / standing charge / fuel
routing). Investigated in the next slice.

This fix is spec-faithful per Appendix L L1-L11 — lodge the cert
data the spec expects; don't rely on absent-data fallbacks for
data that's actually present. Closing the cost residual will let
000480/487/516 land at Δcont < 0.01.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 21:52:46 +00:00
..
domain Cohort residual slice 17: wire Appendix L inputs into 000480 / 487 / 516 2026-05-22 21:52:46 +00:00
fetchers added potential file scaffolding: 2026-05-15 10:56:53 +00:00
repos added potential file scaffolding: 2026-05-15 10:56:53 +00:00
utils added potential file scaffolding: 2026-05-15 10:56:53 +00:00
README.md added potential file scaffolding: 2026-05-15 10:56:53 +00:00

Shared packages

Workspace packages consumed by services/*. Each package is its own Python distribution with its own pyproject.toml; services import via the workspace dependency mechanism ({ workspace = true }).

Package Purpose
domain/ Shared domain types — Property, BaselinePerformance, Plan, Scenario, EpcPropertyData, etc. No persistence, no IO, no business logic.
repos/ Persistence layer — one repo per aggregate. Owns the SQL. Depends on domain.
fetchers/ External API clients (gov EPC, Ofgem, Google Solar, etc.). Depend on domain for response shapes.
utils/ Cross-cutting infra — logging, S3, CloudWatch URL builders, SQS task helpers.

Adding a new shared package

Only when a real second consumer materialises. Don't pre-shatter (repos-epc, repos-property, ...) — split when a deployment needs to drop a dep, not before.

See ../ara_backend_design.md §11 for the broader monorepo layout and ../CONTEXT.md for the domain glossary that names the types living in domain/.