Model/packages/domain
Khalim Conn-Kowlessar cd94da4d2e Slice 26: §7 LINE_92/93 closure — RdSAP §15 area rounding on living area
LINE_91 in the worksheet is `living_area / (4)`, where living_area itself
is the §15-rounded materialisation of `Table 27 fraction × TFA`. RdSAP
§9.2 (p.52): "The living area is then the fraction multiplied by the
total floor area." §15 (p.66) lists "All internal floor areas and living
area: 2 d.p." So the actual LINE_91 fed to the §7 zone blend is
`round_half_up(Table_27 × TFA, 2) / TFA`, not the raw Table 27 entry.

The roundtrip explains why the 4 holdout fixtures lodge LINE_91 = 0.3001
or 0.2501 instead of the Table 27 values 0.30 / 0.25:
  000474: 0.30 × 56.79 → 17.04 / 56.79 = 0.3001
  000477: 0.25 × 77.58 → 19.40 / 77.58 = 0.2501
  000490: 0.25 × 66.06 → 16.52 / 66.06 = 0.2501

`_living_area_fraction` now takes TFA and materialises + rounds + divides;
`_living_area_fraction_default` retains the bare Table 27 lookup. Existing
`_round_half_up` from heat_transmission is the right utility (same §15
boundary, same half-up convention).

Scoreboard: §7 cascade pins 52/60 → 60/60 (closes LINE_92/93 on 000474,
000477, 000480, 000490 — and tightens the already-passing 000487/000516
combinations). Full cascade: 304/312 → 312/312 (100%).

e2e SapResult: 27/66 → 56/66 (continuous SAP, ECF, fuel cost, space
heating kWh now close on 5/6 fixtures; 000487 still has unrelated
downstream defects, all 6 CO2 fails await §12).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 23:39:20 +00:00
..
src/domain Slice 26: §7 LINE_92/93 closure — RdSAP §15 area rounding on living area 2026-05-23 23:39:20 +00:00
pyproject.toml slice 13: to_rows(properties) returns pd.DataFrame 2026-05-16 16:43:28 +00:00
README.md added potential file scaffolding: 2026-05-15 10:56:53 +00:00

domna-domain

Shared domain types — Property, Properties, BaselinePerformance, Plan, PlanPhase, Scenario, ScenarioPhase, ScenarioSnapshot, Recommendation, OptimisedPackage, EpcPropertyData, etc.

Boundary: types only. No persistence, no IO, no business logic. Other packages and services depend on domna-domain; this package depends on nothing internal.

Domain definitions live in ../../CONTEXT.md. New types added here must match the glossary terms.

Layout

src/domain/
├── __init__.py
├── property.py             # Property, Properties, PropertyIdentity
├── site_notes.py
├── landlord_overrides.py
├── baseline_performance.py # lodged + effective pair (ADR-0004)
├── plan.py                 # Plan, PlanPhase, OptimisedPackage
├── scenario.py             # Scenario, ScenarioPhase, ScenarioSnapshot (ADR-0005)
├── recommendation.py
├── geospatial.py
├── solar.py
├── anomaly_flags.py
└── ml/
    ├── __init__.py
    ├── transform.py        # EpcMlTransform (versioned per §8.3)
    └── schema.py

When datatypes/epc/domain/ folds in, the EPC schema types move under src/domain/epc/.