Model/packages
Khalim Conn-Kowlessar 6ea5727a4e Dimensions: storey_count is dwelling height (max across parts), not sum
SAP §2 (9) "ns" is the dwelling height — the tallest part — which drives
the (10) additional-infiltration adjustment. Pre-fix code summed
`len(sap_floor_dimensions)` across parts and incremented for every
sap_room_in_roof block, so a 2-storey main + 1-storey side extension
returned ns=3 instead of 2, and a 2-part RR-bearing cert could return
ns=4 or 5. The (10) ach output overstated by 0.1 per spurious storey.

Fix tracks per-part `(floor_count + 1 if RR else 0)` and emits
`max(per_part)`. TFA and volume sums on §1 are unaffected — those are
genuine Σ per RdSAP §3.9.1.

Surfaced by Elmhurst 000474 (2-storey + 2 side extensions): worksheet
says ns=2; we previously had to pass `storey_count=fixture.LINE_9_STOREYS`
explicitly in the §2 Elmhurst conformance test. With the fix, the test
now derives `storey_count` from `dims.storey_count` and the
`LINE_9_STOREYS` field cross-checks the derivation against (9).

Tests:
- New: dwelling_storey_count_is_max_across_parts_not_sum (2-storey main
  + 1-storey ext expects ns=2)
- New: room_in_roof_on_main_adds_one_to_dwelling_storey_count_only_once
  (main with RR + ext without RR expects ns=3, not 5)
- Updated: main_plus_extension_sums_areas_perimeters_and_walls assertion
  ns==2 → ns==1 (both parts single-storey)
- Updated: all_rir_shapes_apply_section_1_2_45m_convention_uniformly —
  storey_delta is now ≤1 not len(parts_with_rr); TFA/volume deltas
  remain Σ per the spec
- Updated: §2 Elmhurst test consumes dims.storey_count + asserts
  dims.storey_count == fixture.LINE_9_STOREYS as an Arrange precondition

826 tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 10:27:38 +00:00
..
domain Dimensions: storey_count is dwelling height (max across parts), not sum 2026-05-20 10:27:38 +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/.