From 68401c517a415e6260aafdd1a22dce63fe482117 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 26 May 2026 13:01:35 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20lift-and-shift=20packages/domain/sr?= =?UTF-8?q?c/domain/ml=20=E2=86=92=20domain/sap10=5Fml?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sibling migration to the sap10_calculator move — `domain.ml` now lives at the root-level layout (`domain/sap10_ml/`) matching the pattern already used by `domain.addresses`, `domain.tasks`, `domain.postcode`, and `domain.sap10_calculator`. Changes: - `git mv packages/domain/src/domain/ml → domain/sap10_ml` (19 files; history preserved). - Subpackage rename: `domain.ml` → `domain.sap10_ml`. 32 references rewritten across .py and .md files: 11 internal + 21 external (datatypes/epc/domain/mapper.py, 14 files in domain/sap10_calculator, 2 backend tests, 2 ADRs, 1 README, 1 design doc). - Path-string updates: `pytest.ini` testpath `packages/domain/src/domain/ml/tests` → `domain/sap10_ml/tests` so ML tests stay in the default auto-discovered sweep. `CONTEXT.md` also updated. `packages/domain/src/domain/` is now empty — the workspace `domain/` tree has been fully migrated. Together with the `domain/__init__.py` deletions from the sap10_calculator commit (29ac35cc), `domain` is now a single root-level namespace package with subpackages {addresses, sap10_calculator, sap10_ml, tasks} + the standalone `postcode.py` module. Verified: - Focused sweep (backend mapper-chain + sap10_calculator worksheet e2e + golden fixtures): 99 passed / 19 failed — identical baseline. - Wider sweep (all sap10_calculator + sap10_ml): 1654 passed / 20 failed (same pre-existing failures). - domain/sap10_ml/tests: 210/210 PASSED at new path. - Pyright net-zero: heat_transmission.py 13, cert_to_inputs.py 35, mapper.py 33, rdsap_uvalues.py 1 (all unchanged from baseline). Note: `packages/domain/pyproject.toml` still declares `packages = ["src/domain"]` for the hatchling wheel — that target directory is now empty and the wheel build is effectively a no-op. Retiring the workspace package or repointing the wheel is a follow-up. Co-Authored-By: Claude Opus 4.7 --- CONTEXT.md | 2 +- ara_backend_design.md | 2 +- .../tests/test_elmhurst_end_to_end.py | 4 ++-- datatypes/epc/domain/mapper.py | 4 ++-- docs/adr/0009-deterministic-sap-calculator.md | 4 ++-- ...-sap10-calculator-spec-target-and-validation.md | 4 ++-- domain/sap10_calculator/README.md | 2 +- domain/sap10_calculator/rdsap/cert_to_inputs.py | 8 ++++---- .../rdsap/tests/test_cert_to_inputs.py | 2 +- domain/sap10_calculator/tables/table_12.py | 2 +- .../worksheet/heat_transmission.py | 6 +++--- .../worksheet/tests/_elmhurst_worksheet_000474.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_000477.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_000480.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_000487.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_000490.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_000516.py | 2 +- .../worksheet/tests/_elmhurst_worksheet_001479.py | 2 +- .../worksheet/tests/test_dimensions.py | 2 +- .../worksheet/tests/test_heat_transmission.py | 4 ++-- .../worksheet/tests/test_internal_gains.py | 2 +- .../worksheet/tests/test_solar_gains.py | 2 +- .../src/domain/ml => domain/sap10_ml}/__init__.py | 0 .../src/domain/ml => domain/sap10_ml}/demand.py | 4 ++-- .../src/domain/ml => domain/sap10_ml}/ecf.py | 2 +- .../src/domain/ml => domain/sap10_ml}/envelope.py | 2 +- .../domain/ml => domain/sap10_ml}/rdsap_uvalues.py | 0 .../ml => domain/sap10_ml}/sap_efficiencies.py | 0 .../src/domain/ml => domain/sap10_ml}/schema.py | 0 .../ml => domain/sap10_ml}/tests/__init__.py | 0 .../ml => domain/sap10_ml}/tests/_fixtures.py | 0 .../ml => domain/sap10_ml}/tests/test_demand.py | 2 +- .../ml => domain/sap10_ml}/tests/test_ecf.py | 2 +- .../ml => domain/sap10_ml}/tests/test_envelope.py | 4 ++-- .../sap10_ml}/tests/test_rdsap_uvalues.py | 2 +- .../sap10_ml}/tests/test_sap_efficiencies.py | 2 +- .../ml => domain/sap10_ml}/tests/test_transform.py | 8 ++++---- .../sap10_ml}/tests/test_ventilation.py | 2 +- .../src/domain/ml => domain/sap10_ml}/transform.py | 14 +++++++------- .../src/domain/ml => domain/sap10_ml}/ucl.py | 0 .../domain/ml => domain/sap10_ml}/ventilation.py | 0 pytest.ini | 2 +- 42 files changed, 55 insertions(+), 55 deletions(-) rename {packages/domain/src/domain/ml => domain/sap10_ml}/__init__.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/demand.py (98%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/ecf.py (98%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/envelope.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/rdsap_uvalues.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/sap_efficiencies.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/schema.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/__init__.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/_fixtures.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_demand.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_ecf.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_envelope.py (98%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_rdsap_uvalues.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_sap_efficiencies.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_transform.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/tests/test_ventilation.py (98%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/transform.py (99%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/ucl.py (100%) rename {packages/domain/src/domain/ml => domain/sap10_ml}/ventilation.py (100%) diff --git a/CONTEXT.md b/CONTEXT.md index 3c02e7e8..54e66032 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -132,7 +132,7 @@ _Avoid_: outlier, mismatch, divergence flag ### ML training **EPC ML Transform**: -The versioned class at `packages/domain/src/domain/ml/transform.py` that maps an EpcPropertyData to a fixed-width row of features + targets. The single ML-data contract between this repo and the AutoGluon training repo. Owns the windows compression, building-parts compression, Top-N Code Taxonomy, and UCL folding decisions. Each version is tagged on the deployed scoring lambda; a mismatch is a deploy-time fail. +The versioned class at `domain/sap10_ml/transform.py` that maps an EpcPropertyData to a fixed-width row of features + targets. The single ML-data contract between this repo and the AutoGluon training repo. Owns the windows compression, building-parts compression, Top-N Code Taxonomy, and UCL folding decisions. Each version is tagged on the deployed scoring lambda; a mismatch is a deploy-time fail. _Avoid_: feature builder, ML mapper, EPC vectoriser **Feature Schema Version**: diff --git a/ara_backend_design.md b/ara_backend_design.md index de64cc1d..f3d11696 100644 --- a/ara_backend_design.md +++ b/ara_backend_design.md @@ -412,7 +412,7 @@ For tests, each repo has a `FakeXRepo` companion backed by a dict. Service unit | Concern | Owner | |---|---| -| Defining the EPC → features transform | **This repo** (`ara.domain.ml.EpcMlTransform`) | +| Defining the EPC → features transform | **This repo** (`ara.domain.sap10_ml.EpcMlTransform`) | | Loading data, applying transform, writing training parquet to S3 | **This repo** (sub-PRD (ii) batch job) | | Training, hyperparameter search, deployment | **Autogluon repo** | | Scoring at modelling time | **This repo** (`FeatureBuilder` calls `EpcMlTransform`, sends DataFrame to deployed lambda) | diff --git a/backend/documents_parser/tests/test_elmhurst_end_to_end.py b/backend/documents_parser/tests/test_elmhurst_end_to_end.py index c9ae0e41..133c7816 100644 --- a/backend/documents_parser/tests/test_elmhurst_end_to_end.py +++ b/backend/documents_parser/tests/test_elmhurst_end_to_end.py @@ -140,12 +140,12 @@ class TestBuildingPart: def test_wall_construction(self, result: EpcPropertyData) -> None: # SAP10 wall_construction integer: 4 = Cavity (per - # domain.ml.rdsap_uvalues.WALL_CAVITY). + # domain.sap10_ml.rdsap_uvalues.WALL_CAVITY). assert result.sap_building_parts[0].wall_construction == 4 def test_wall_insulation_type(self, result: EpcPropertyData) -> None: # SAP10 wall_insulation_type integer: 2 = Filled cavity (per - # domain.ml.rdsap_uvalues.WALL_INSULATION_FILLED_CAVITY). + # domain.sap10_ml.rdsap_uvalues.WALL_INSULATION_FILLED_CAVITY). assert result.sap_building_parts[0].wall_insulation_type == 2 def test_wall_thickness_measured(self, result: EpcPropertyData) -> None: diff --git a/datatypes/epc/domain/mapper.py b/datatypes/epc/domain/mapper.py index c3427666..69e557a6 100644 --- a/datatypes/epc/domain/mapper.py +++ b/datatypes/epc/domain/mapper.py @@ -1974,7 +1974,7 @@ def _leading_code(value: str) -> str: # Elmhurst wall-type codes mapped to SAP10 wall_construction integers -# (matches the constants defined in domain.ml.rdsap_uvalues). +# (matches the constants defined in domain.sap10_ml.rdsap_uvalues). _ELMHURST_WALL_CODE_TO_SAP10: Dict[str, int] = { "ST": 1, # Stone (granite/sandstone) — placeholder; sandstone vs granite # ambiguity resolved downstream via walls[].description. @@ -1990,7 +1990,7 @@ _ELMHURST_WALL_CODE_TO_SAP10: Dict[str, int] = { # Elmhurst wall-insulation-type codes mapped to the SAP10 integer enum -# documented at domain.ml.rdsap_uvalues.WALL_INSULATION_FILLED_CAVITY. +# documented at domain.sap10_ml.rdsap_uvalues.WALL_INSULATION_FILLED_CAVITY. _ELMHURST_INSULATION_CODE_TO_SAP10: Dict[str, int] = { "E": 1, # External wall insulation "F": 2, # Filled cavity diff --git a/docs/adr/0009-deterministic-sap-calculator.md b/docs/adr/0009-deterministic-sap-calculator.md index f3f1836a..8727e7f6 100644 --- a/docs/adr/0009-deterministic-sap-calculator.md +++ b/docs/adr/0009-deterministic-sap-calculator.md @@ -79,7 +79,7 @@ domain/sap10_calculator/ cascade_defaults.py # the RdSAP10 "assume-typical" rules (currently in rdsap_uvalues.py) ``` -The existing `domain.ml.*` modules stay where they are during Session A; they continue serving the live ML pipeline. Session B promotes them into `domain.sap10_calculator.*` once parity is reached. +The existing `domain.sap10_ml.*` modules stay where they are during Session A; they continue serving the live ML pipeline. Session B promotes them into `domain.sap10_calculator.*` once parity is reached. ## Sap10Calculator interface @@ -147,7 +147,7 @@ Re-derivation work is bounded — a few hundred numbers across tables — and th ## Consequences -- A new top-level domain area `domain.sap10_calculator.*` is introduced; over Sessions B/C it absorbs `domain.ml.{envelope,demand,ecf,rdsap_uvalues,sap_efficiencies,ventilation}.py`. The ML transform stops shipping those as standalone features once the residual head takes over. +- A new top-level domain area `domain.sap10_calculator.*` is introduced; over Sessions B/C it absorbs `domain.sap10_ml.{envelope,demand,ecf,rdsap_uvalues,sap_efficiencies,ventilation}.py`. The ML transform stops shipping those as standalone features once the residual head takes over. - The codebase carries two SAP outputs: cert-reported `sap_score` (ground truth at training time) and calculator-emitted `sap_score` (ground truth at inference time for any RdSAP cert input). The product layer chooses; for "score this hypothetical post-retrofit state", calculator wins. - The deterministic calculator is **version-bound to SAP 10.3.** A future SAP 10.4 is a calculator MAJOR bump and an ADR. The ML residual head is SAP-version-agnostic only insofar as the residual distribution it learns stays stationary; in practice a spec bump retrains the residual head. - Spec PDFs live in `docs/sap-spec/` (this repo). The repo now carries the canonical reference for what the calculator computes. License: SAP 10.3 © Crown copyright 2026; RdSAP 10 © BRE — both are public-interest references for SAP-compliant software, included for traceability. diff --git a/docs/adr/0010-sap10-calculator-spec-target-and-validation.md b/docs/adr/0010-sap10-calculator-spec-target-and-validation.md index 7dd52c7c..b6d4a375 100644 --- a/docs/adr/0010-sap10-calculator-spec-target-and-validation.md +++ b/docs/adr/0010-sap10-calculator-spec-target-and-validation.md @@ -120,12 +120,12 @@ Two engine bugs surfaced during the wire-up: - **000490 SAP integer + fuel cost tests xfail** (strict). Appendix L closure is spec-faithful (lighting kWh 614 → 171 matches U985 (232)=171.4217 to abs=1e-4), but the cost residual widens from -4.7% to -12.9% and SAP delta widens 3 → 6. The remaining residual is from other broken components on this fixture — primary suspects: fuel pricing for the pre-2025-07-01 cohort (Table 32 lodge-date snapshot semantics), main heating fuel +2.5% overshoot, Table D1/D2/D3 Ecodesign corrections, Appendix N heat-pump cascade. Per `feedback-e2e-validation-philosophy` memory: don't widen, hunt. Tests re-enable when each next component closes. - **Golden fixture `_PE_TOLERANCE_KWH_PER_M2` widened 30 → 35** to absorb the elec-PEF × lighting-Δ contribution (~4 kWh/m²) on the non-Elmhurst cohort. Pre-Appendix-L baseline residuals already sat near -28 kWh/m² from unrelated components on those certs. Tightens back when the dominant remaining components close. - **Per-component worksheet-level pins land**: `result.lighting_kwh_per_yr == U985 (232)` at abs=1e-4 for the 2 e2e fixtures, and `InternalGainsResult.lighting_kwh_per_yr == U985 (232)` at abs=1e-4 for all 6 §5 fixtures. New per-fixture constant `LINE_232_LIGHTING_KWH_PER_YR` pins each lodged value. -- **`predicted_lighting_kwh` kept** in `domain/ml/demand.py` with a deprecation note. Still used by `domain.ml.ecf.energy_cost_factor` and `domain.ml.transform.transform_to_predictions` — both legacy ML pre-SAP-rewrite call sites; rip when those migrate. +- **`predicted_lighting_kwh` kept** in `domain/ml/demand.py` with a deprecation note. Still used by `domain.sap10_ml.ecf.energy_cost_factor` and `domain.sap10_ml.transform.transform_to_predictions` — both legacy ML pre-SAP-rewrite call sites; rip when those migrate. ### Deferred work (named in Appendix L slice 3) - **000490 / cohort SAP-integer closure (residual hunt).** Next ticket. Suspects above. Driven by user's next batch of test fixtures (battle-testing the engine) → emergent residual identification. -- **`predicted_lighting_kwh` deletion.** Future cleanup ticket once `domain.ml.ecf` + `domain.ml.transform` are off the legacy heuristic. +- **`predicted_lighting_kwh` deletion.** Future cleanup ticket once `domain.sap10_ml.ecf` + `domain.sap10_ml.transform` are off the legacy heuristic. - **RdSAP10 → API integration test.** End-state e2e harness: RdSAP API response → `cert_to_inputs` → `calculate_sap_from_inputs` → SAP integer = lodged integer. Once enough cohort fixtures pass delta=0 on isolated components. ## Amendment — Cohort residual hunt + SAP 10.2 rating constants (2026-05-22) diff --git a/domain/sap10_calculator/README.md b/domain/sap10_calculator/README.md index 3beeb5da..d2a3d0ef 100644 --- a/domain/sap10_calculator/README.md +++ b/domain/sap10_calculator/README.md @@ -110,7 +110,7 @@ So a 2.91 m upper-storey internal height appears on the worksheet as 3.16 m. Mir - Simplified Type 1 (RR lodged with only `floor_area`) still works via the spec's `A_RR = 12.5 × √(A_RR_floor/1.5)` formula at `u_rr_default_all_elements` (Table 18 col 4). Detailed lodgement supersedes when present. ### Party wall U mapping -`party_wall_construction` integer codes resolve via `domain.ml.rdsap_uvalues.u_party_wall`: +`party_wall_construction` integer codes resolve via `domain.sap10_ml.rdsap_uvalues.u_party_wall`: - `0` (Unknown / "Unable to determine") → 0.25 W/m²K - `1` (Stone granite) / `3` (Solid brick) / `5` (Timber frame) / `6` (System built) → 0.0 - `4` (Cavity, unfilled) → 0.5 diff --git a/domain/sap10_calculator/rdsap/cert_to_inputs.py b/domain/sap10_calculator/rdsap/cert_to_inputs.py index ed5858c3..9dd24fc3 100644 --- a/domain/sap10_calculator/rdsap/cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/cert_to_inputs.py @@ -61,9 +61,9 @@ from datatypes.epc.domain.epc_property_data import ( SapWindow, ) -from domain.ml.demand import predicted_hot_water_kwh -from domain.ml.rdsap_uvalues import Country, u_floor -from domain.ml.sap_efficiencies import ( +from domain.sap10_ml.demand import predicted_hot_water_kwh +from domain.sap10_ml.rdsap_uvalues import Country, u_floor +from domain.sap10_ml.sap_efficiencies import ( seasonal_efficiency, water_heating_efficiency as _legacy_water_heating_efficiency, ) @@ -805,7 +805,7 @@ def _other_fuel_cost_gbp_per_kwh( # Water-heating codes that say "inherit from the main system" — the # `seasonal_efficiency` cascade returns 0 as a sentinel for these in the -# legacy `domain.ml.sap_efficiencies` module. We need to inherit through +# legacy `domain.sap10_ml.sap_efficiencies` module. We need to inherit through # the SAME cascade the main heating uses, including the main_heating_ # category fallback (e.g. heat pumps return 2.30 via category 4). _WATER_INHERIT_FROM_MAIN_CODES: Final[frozenset[int]] = frozenset({901, 902, 914}) diff --git a/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py b/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py index 8b0553ae..f7680043 100644 --- a/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py @@ -20,7 +20,7 @@ import pytest from datatypes.epc.domain.epc_property_data import MainHeatingDetail, PhotovoltaicArray -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_building_part, make_floor_dimension, make_minimal_sap10_epc, diff --git a/domain/sap10_calculator/tables/table_12.py b/domain/sap10_calculator/tables/table_12.py index 8b83ddbc..b6248317 100644 --- a/domain/sap10_calculator/tables/table_12.py +++ b/domain/sap10_calculator/tables/table_12.py @@ -202,7 +202,7 @@ _DEFAULT_CO2_KG_PER_KWH: Final[float] = 0.210 # mains gas baseline # Gov EPC API main_fuel_type → SAP 10.3 Table 12 fuel code. Lifted from -# the SAP 10.2 mapper (`domain.ml.sap_efficiencies._API_TO_TABLE32`) — +# the SAP 10.2 mapper (`domain.sap10_ml.sap_efficiencies._API_TO_TABLE32`) — # the API enum and Table 32/12 codes are unchanged across spec versions. API_FUEL_TO_TABLE_12: Final[dict[int, int]] = { 0: 30, 1: 1, 2: 2, 3: 3, 4: 4, 5: 15, 6: 20, 7: 23, 8: 21, 9: 10, diff --git a/domain/sap10_calculator/worksheet/heat_transmission.py b/domain/sap10_calculator/worksheet/heat_transmission.py index e6bc2572..f59e89a9 100644 --- a/domain/sap10_calculator/worksheet/heat_transmission.py +++ b/domain/sap10_calculator/worksheet/heat_transmission.py @@ -23,13 +23,13 @@ Worksheet line mapping (SAP 10.2 §3, canonical xlsx rows 121-207): (36) thermal bridging = y × Σ exposed area (RdSAP Table 21) (37) total fabric heat loss = (33) + (36) -This is the calculator-vocabulary sibling of `domain.ml.envelope`. During +This is the calculator-vocabulary sibling of `domain.sap10_ml.envelope`. During Session A both modules coexist — the legacy envelope.py continues to feed the ML transform's `envelope_heat_loss_w_per_k` physics-feature. Session B will retire envelope.py in favour of this module (ADR-0009 §"Module layout"). -U-value lookups cascade through `domain.ml.rdsap_uvalues` — migrating to +U-value lookups cascade through `domain.sap10_ml.rdsap_uvalues` — migrating to `domain.sap10_calculator.rdsap.cascade_defaults` in Session B. Reference: SAP 10.2 specification §3 (pages 17-22); RdSAP 10 §5 (Tables @@ -49,7 +49,7 @@ from datatypes.epc.domain.epc_property_data import ( SapRoofWindow, ) -from domain.ml.rdsap_uvalues import ( +from domain.sap10_ml.rdsap_uvalues import ( Country, WALL_UNKNOWN, _described_as_insulated, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py index 8a0012a5..dca08d79 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py @@ -31,7 +31,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py index 446e1f90..b366b0d3 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py @@ -29,7 +29,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py index d3ebd2e6..59ebb8f9 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py @@ -30,7 +30,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py index 32ebc83d..94644d25 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py @@ -28,7 +28,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py index 039eb534..50a37631 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py @@ -33,7 +33,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py index 82ff058f..15533dbf 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py @@ -36,7 +36,7 @@ from datatypes.epc.domain.epc_property_data import ( ShowerOutlet, ShowerOutlets, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py index ac197ceb..37faca80 100644 --- a/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py @@ -70,7 +70,7 @@ from datatypes.epc.domain.epc_property_data import ( SapVentilation, SapWindow, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_main_heating_detail, make_minimal_sap10_epc, make_sap_heating, diff --git a/domain/sap10_calculator/worksheet/tests/test_dimensions.py b/domain/sap10_calculator/worksheet/tests/test_dimensions.py index 893f7dc8..e28ec662 100644 --- a/domain/sap10_calculator/worksheet/tests/test_dimensions.py +++ b/domain/sap10_calculator/worksheet/tests/test_dimensions.py @@ -21,7 +21,7 @@ from datatypes.epc.domain.epc_property_data import ( SapRoomInRoof, ) from datatypes.epc.domain.mapper import EpcPropertyDataMapper -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_building_part, make_floor_dimension, make_minimal_sap10_epc, diff --git a/domain/sap10_calculator/worksheet/tests/test_heat_transmission.py b/domain/sap10_calculator/worksheet/tests/test_heat_transmission.py index e3f3e0ef..b3d43bf1 100644 --- a/domain/sap10_calculator/worksheet/tests/test_heat_transmission.py +++ b/domain/sap10_calculator/worksheet/tests/test_heat_transmission.py @@ -7,7 +7,7 @@ a typed `HeatTransmission` breakdown so callers can audit each worksheet contribution. U-values cascade through the RdSAP 10 §5 defaults (currently implemented -in `domain.ml.rdsap_uvalues` — migrates to `domain.sap10_calculator.rdsap.cascade_defaults` +in `domain.sap10_ml.rdsap_uvalues` — migrates to `domain.sap10_calculator.rdsap.cascade_defaults` in Session B). Reference: SAP 10.3 specification §3 (pages 17-22); @@ -25,7 +25,7 @@ from datatypes.epc.domain.epc_property_data import ( SapRoomInRoofSurface, ) -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.tests._fixtures import ( make_building_part, make_floor_dimension, make_minimal_sap10_epc, diff --git a/domain/sap10_calculator/worksheet/tests/test_internal_gains.py b/domain/sap10_calculator/worksheet/tests/test_internal_gains.py index 3107c7a1..11298313 100644 --- a/domain/sap10_calculator/worksheet/tests/test_internal_gains.py +++ b/domain/sap10_calculator/worksheet/tests/test_internal_gains.py @@ -43,7 +43,7 @@ from datatypes.epc.domain.epc_property_data import ( SapHeating, SapWindow, ) -from domain.ml.tests._fixtures import make_minimal_sap10_epc +from domain.sap10_ml.tests._fixtures import make_minimal_sap10_epc from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id diff --git a/domain/sap10_calculator/worksheet/tests/test_solar_gains.py b/domain/sap10_calculator/worksheet/tests/test_solar_gains.py index 3c2a19cc..2298f554 100644 --- a/domain/sap10_calculator/worksheet/tests/test_solar_gains.py +++ b/domain/sap10_calculator/worksheet/tests/test_solar_gains.py @@ -18,7 +18,7 @@ from datatypes.epc.domain.epc_property_data import ( SapWindow, WindowTransmissionDetails, ) -from domain.ml.tests._fixtures import make_minimal_sap10_epc, make_window +from domain.sap10_ml.tests._fixtures import make_minimal_sap10_epc, make_window from domain.sap10_calculator.worksheet.internal_gains import OvershadingCategory from domain.sap10_calculator.worksheet.solar_gains import ( Orientation, diff --git a/packages/domain/src/domain/ml/__init__.py b/domain/sap10_ml/__init__.py similarity index 100% rename from packages/domain/src/domain/ml/__init__.py rename to domain/sap10_ml/__init__.py diff --git a/packages/domain/src/domain/ml/demand.py b/domain/sap10_ml/demand.py similarity index 98% rename from packages/domain/src/domain/ml/demand.py rename to domain/sap10_ml/demand.py index 8a90805a..26da2465 100644 --- a/packages/domain/src/domain/ml/demand.py +++ b/domain/sap10_ml/demand.py @@ -235,8 +235,8 @@ def predicted_lighting_kwh( cascade is in `domain.sap10_calculator.worksheet.internal_gains.annual_lighting_kwh` and is what `cert_to_inputs` now plumbs into `inputs.lighting_kwh_per_yr`. This heuristic over-counts ~3× on the Elmhurst cohort (528 vs 140 kWh - on 000474). Kept only for `domain.ml.ecf.energy_cost_factor` and - `domain.ml.transform.transform_to_predictions` — legacy ML predictor + on 000474). Kept only for `domain.sap10_ml.ecf.energy_cost_factor` and + `domain.sap10_ml.transform.transform_to_predictions` — legacy ML predictor callsites that pre-date the SAP rewrite. Rip when those migrate. See ADR-0010 amendment "Appendix L lighting (2026-05-22)". """ diff --git a/packages/domain/src/domain/ml/ecf.py b/domain/sap10_ml/ecf.py similarity index 98% rename from packages/domain/src/domain/ml/ecf.py rename to domain/sap10_ml/ecf.py index 16fe15ad..851d01f5 100644 --- a/packages/domain/src/domain/ml/ecf.py +++ b/domain/sap10_ml/ecf.py @@ -15,7 +15,7 @@ from __future__ import annotations from math import log10 from typing import Final, Optional -from domain.ml.sap_efficiencies import fuel_unit_price_p_per_kwh +from domain.sap10_ml.sap_efficiencies import fuel_unit_price_p_per_kwh # SAP10 deflator applied to total cost before the rating equation (Table 32). diff --git a/packages/domain/src/domain/ml/envelope.py b/domain/sap10_ml/envelope.py similarity index 99% rename from packages/domain/src/domain/ml/envelope.py rename to domain/sap10_ml/envelope.py index b43b140e..fc6a726d 100644 --- a/packages/domain/src/domain/ml/envelope.py +++ b/domain/sap10_ml/envelope.py @@ -15,7 +15,7 @@ from typing import Any, Optional from datatypes.epc.domain.epc_property_data import SapBuildingPart -from domain.ml.rdsap_uvalues import ( +from domain.sap10_ml.rdsap_uvalues import ( Country, WALL_CAVITY, WALL_UNKNOWN, diff --git a/packages/domain/src/domain/ml/rdsap_uvalues.py b/domain/sap10_ml/rdsap_uvalues.py similarity index 100% rename from packages/domain/src/domain/ml/rdsap_uvalues.py rename to domain/sap10_ml/rdsap_uvalues.py diff --git a/packages/domain/src/domain/ml/sap_efficiencies.py b/domain/sap10_ml/sap_efficiencies.py similarity index 100% rename from packages/domain/src/domain/ml/sap_efficiencies.py rename to domain/sap10_ml/sap_efficiencies.py diff --git a/packages/domain/src/domain/ml/schema.py b/domain/sap10_ml/schema.py similarity index 100% rename from packages/domain/src/domain/ml/schema.py rename to domain/sap10_ml/schema.py diff --git a/packages/domain/src/domain/ml/tests/__init__.py b/domain/sap10_ml/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/ml/tests/__init__.py rename to domain/sap10_ml/tests/__init__.py diff --git a/packages/domain/src/domain/ml/tests/_fixtures.py b/domain/sap10_ml/tests/_fixtures.py similarity index 100% rename from packages/domain/src/domain/ml/tests/_fixtures.py rename to domain/sap10_ml/tests/_fixtures.py diff --git a/packages/domain/src/domain/ml/tests/test_demand.py b/domain/sap10_ml/tests/test_demand.py similarity index 99% rename from packages/domain/src/domain/ml/tests/test_demand.py rename to domain/sap10_ml/tests/test_demand.py index 05206d6e..a0fcf897 100644 --- a/packages/domain/src/domain/ml/tests/test_demand.py +++ b/domain/sap10_ml/tests/test_demand.py @@ -2,7 +2,7 @@ import pytest -from domain.ml.demand import ( +from domain.sap10_ml.demand import ( predicted_hot_water_kwh, predicted_lighting_kwh, predicted_space_heating_kwh, diff --git a/packages/domain/src/domain/ml/tests/test_ecf.py b/domain/sap10_ml/tests/test_ecf.py similarity index 99% rename from packages/domain/src/domain/ml/tests/test_ecf.py rename to domain/sap10_ml/tests/test_ecf.py index b429e030..305d3604 100644 --- a/packages/domain/src/domain/ml/tests/test_ecf.py +++ b/domain/sap10_ml/tests/test_ecf.py @@ -5,7 +5,7 @@ from math import log10 import pytest -from domain.ml.ecf import ( +from domain.sap10_ml.ecf import ( predicted_ecf, predicted_log10_ecf, predicted_pv_generation_kwh, diff --git a/packages/domain/src/domain/ml/tests/test_envelope.py b/domain/sap10_ml/tests/test_envelope.py similarity index 98% rename from packages/domain/src/domain/ml/tests/test_envelope.py rename to domain/sap10_ml/tests/test_envelope.py index dd549b6f..3f1eecf1 100644 --- a/packages/domain/src/domain/ml/tests/test_envelope.py +++ b/domain/sap10_ml/tests/test_envelope.py @@ -6,8 +6,8 @@ test cases stay close to the shape transform.py sees on a real cert. import pytest -from domain.ml.envelope import envelope_heat_loss_w_per_k -from domain.ml.tests._fixtures import make_building_part, make_floor_dimension +from domain.sap10_ml.envelope import envelope_heat_loss_w_per_k +from domain.sap10_ml.tests._fixtures import make_building_part, make_floor_dimension def test_envelope_single_storey_no_windows_no_doors_age_g_cavity_returns_expected_w_per_k() -> None: diff --git a/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py b/domain/sap10_ml/tests/test_rdsap_uvalues.py similarity index 99% rename from packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py rename to domain/sap10_ml/tests/test_rdsap_uvalues.py index 571d27ab..01cd98be 100644 --- a/packages/domain/src/domain/ml/tests/test_rdsap_uvalues.py +++ b/domain/sap10_ml/tests/test_rdsap_uvalues.py @@ -20,7 +20,7 @@ from typing import Optional import pytest -from domain.ml.rdsap_uvalues import ( +from domain.sap10_ml.rdsap_uvalues import ( Country, WALL_CAVITY, WALL_INSULATION_FILLED_CAVITY, diff --git a/packages/domain/src/domain/ml/tests/test_sap_efficiencies.py b/domain/sap10_ml/tests/test_sap_efficiencies.py similarity index 99% rename from packages/domain/src/domain/ml/tests/test_sap_efficiencies.py rename to domain/sap10_ml/tests/test_sap_efficiencies.py index f32e9bd7..76f513b9 100644 --- a/packages/domain/src/domain/ml/tests/test_sap_efficiencies.py +++ b/domain/sap10_ml/tests/test_sap_efficiencies.py @@ -11,7 +11,7 @@ Helpers never raise on missing codes; they fall back to typical-fuel values. import pytest -from domain.ml.sap_efficiencies import ( +from domain.sap10_ml.sap_efficiencies import ( fuel_unit_price_p_per_kwh, seasonal_efficiency, water_heating_efficiency, diff --git a/packages/domain/src/domain/ml/tests/test_transform.py b/domain/sap10_ml/tests/test_transform.py similarity index 99% rename from packages/domain/src/domain/ml/tests/test_transform.py rename to domain/sap10_ml/tests/test_transform.py index f87d4b12..8a217fd6 100644 --- a/packages/domain/src/domain/ml/tests/test_transform.py +++ b/domain/sap10_ml/tests/test_transform.py @@ -8,8 +8,8 @@ from datatypes.epc.domain.epc_property_data import ( SapRoomInRoof, WindowTransmissionDetails, ) -from domain.ml.schema import ColumnSpec, TransformSchema -from domain.ml.tests._fixtures import ( +from domain.sap10_ml.schema import ColumnSpec, TransformSchema +from domain.sap10_ml.tests._fixtures import ( make_building_part, make_floor_dimension, make_main_heating_detail, @@ -18,7 +18,7 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.ml.transform import EpcMlTransform +from domain.sap10_ml.transform import EpcMlTransform _EXPECTED_TARGET_DTYPES: dict[str, type] = { @@ -1269,7 +1269,7 @@ def test_schema_advertises_envelope_heat_loss_feature() -> None: def test_to_row_emits_positive_envelope_heat_loss_for_sap10_epc() -> None: # Arrange - from domain.ml.tests._fixtures import make_building_part, make_floor_dimension + from domain.sap10_ml.tests._fixtures import make_building_part, make_floor_dimension main = make_building_part( identifier=BuildingPartIdentifier.MAIN, diff --git a/packages/domain/src/domain/ml/tests/test_ventilation.py b/domain/sap10_ml/tests/test_ventilation.py similarity index 98% rename from packages/domain/src/domain/ml/tests/test_ventilation.py rename to domain/sap10_ml/tests/test_ventilation.py index 55673302..49d0c440 100644 --- a/packages/domain/src/domain/ml/tests/test_ventilation.py +++ b/domain/sap10_ml/tests/test_ventilation.py @@ -9,7 +9,7 @@ fixed m³/h additions; draught-proofed windows reduce the structural baseline. import pytest -from domain.ml.ventilation import ventilation_heat_loss_w_per_k +from domain.sap10_ml.ventilation import ventilation_heat_loss_w_per_k def test_ventilation_bare_masonry_no_openings_returns_structural_baseline_only() -> None: diff --git a/packages/domain/src/domain/ml/transform.py b/domain/sap10_ml/transform.py similarity index 99% rename from packages/domain/src/domain/ml/transform.py rename to domain/sap10_ml/transform.py index 7c7da1a9..cc8c39f6 100644 --- a/packages/domain/src/domain/ml/transform.py +++ b/domain/sap10_ml/transform.py @@ -24,22 +24,22 @@ from datatypes.epc.domain.epc_property_data import ( SapHeating, SapWindow, ) -from domain.ml.demand import ( +from domain.sap10_ml.demand import ( predicted_hot_water_kwh, predicted_lighting_kwh, predicted_space_heating_kwh, ) -from domain.ml.ecf import ( +from domain.sap10_ml.ecf import ( predicted_ecf, predicted_log10_ecf, predicted_pv_generation_kwh, predicted_total_fuel_cost_gbp, ) -from domain.ml.envelope import envelope_heat_loss_w_per_k -from domain.ml.ventilation import ventilation_heat_loss_w_per_k -from domain.ml.sap_efficiencies import seasonal_efficiency, water_heating_efficiency -from domain.ml.schema import ColumnSpec, TransformSchema -from domain.ml.ucl import apply_ucl_correction +from domain.sap10_ml.envelope import envelope_heat_loss_w_per_k +from domain.sap10_ml.ventilation import ventilation_heat_loss_w_per_k +from domain.sap10_ml.sap_efficiencies import seasonal_efficiency, water_heating_efficiency +from domain.sap10_ml.schema import ColumnSpec, TransformSchema +from domain.sap10_ml.ucl import apply_ucl_correction # SAP10 orientation codes: 1=N, 2=NE, 3=E, 4=SE, 5=S, 6=SW, 7=W, 8=NW. diff --git a/packages/domain/src/domain/ml/ucl.py b/domain/sap10_ml/ucl.py similarity index 100% rename from packages/domain/src/domain/ml/ucl.py rename to domain/sap10_ml/ucl.py diff --git a/packages/domain/src/domain/ml/ventilation.py b/domain/sap10_ml/ventilation.py similarity index 100% rename from packages/domain/src/domain/ml/ventilation.py rename to domain/sap10_ml/ventilation.py diff --git a/pytest.ini b/pytest.ini index d9535237..7e2eae9a 100644 --- a/pytest.ini +++ b/pytest.ini @@ -25,6 +25,6 @@ testpaths = etl/epc_clean/tests etl/hubspot/tests etl/spatial/tests - packages/domain/src/domain/ml/tests + domain/sap10_ml/tests markers = integration: mark a test as an integration test