From 29ac35ccbeede8443c648dca1fd59c4f786a4d2c Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 26 May 2026 12:19:27 +0000 Subject: [PATCH] =?UTF-8?q?refactor:=20lift-and-shift=20packages/domain/sr?= =?UTF-8?q?c/domain/sap=20=E2=86=92=20domain/sap10=5Fcalculator?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migration of the SAP 10.2 calculator package from the uv-workspace src-layout (`packages/domain/src/domain/sap`) to the root-level layout (`domain/sap10_calculator`), matching the pattern already used by `domain.addresses` / `domain.tasks` / `domain.postcode`. Changes: - `git mv packages/domain/src/domain/sap → domain/sap10_calculator` (92 files; git auto-detected all as renames so blame/history is preserved). - Subpackage rename: `domain.sap` → `domain.sap10_calculator`. 48 Python files rewritten (`from domain.sap.X` → `from domain.sap10_ calculator.X`); zero remaining `domain.sap` refs after the sed pass. - Path-string updates: 3 .py files (test fixtures + xlsx loader) + 6 markdown docs (CONTEXT.md, 2 ADRs, 3 sap-spec docs, sap10_ calculator/README.md) had hard-coded `packages/domain/src/domain/ sap/...` paths rewritten to `domain/sap10_calculator/...`. - `Path(__file__).parents[N]` rebasing: the old tree was 3 levels deeper than the new one (`packages/domain/src/`), so 4× `parents[7]` became `parents[4]` and 1× `parents[6]` became `parents[3]` across `tables/pcdb/{__init__.py, postcode_weather.py, etl.py}`, `worksheet/tests/_xlsx_loader.py`, and `tests/test_pcdb_etl.py`. - PEP 420 namespace package: deleted both `domain/__init__.py` (root + workspace, both load-bearing only as empty/docstring) so Python combines `domain.sap10_calculator` (root) and `domain.ml` (workspace) into one namespace package. Confirmed via `domain.__path__ == ['/workspaces/model/domain', '/workspaces/model/packages/domain/src/domain']`. Without this, the root `domain/__init__.py` shadowed the workspace one and `domain.ml` was unreachable. Verified: - Full sweep (`backend/documents_parser/tests/test_summary_pdf_ mapper_chain.py + domain/sap10_calculator/worksheet/tests/test_ e2e_elmhurst_sap_score.py + domain/sap10_calculator/rdsap/tests/ test_golden_fixtures.py`): 99 passed / 19 failed — exact same counts as pre-refactor. All 19 failures pre-existing (9 hand-built 001479 + 6 cohort diff + 4 cohort chain non-spec). - Wider sweep (all sap10_calculator + domain.ml): 1654 passed / 20 failed (the +1 vs the focused sweep is the pre-existing `test_roof_insulated_assumed_with_ni_thickness_uses_50mm_per_ section_5_11_4` which was already failing on the previous baseline). - Pyright net-zero on the three load-bearing baselines: `heat_transmission.py` 13, `cert_to_inputs.py` 35, `mapper.py` 33. Lift-and-shift only — no semantic renames (`Sap10Calculator` stays `Sap10Calculator`), no testpaths edits in pytest.ini (sap tests continue to be invoked by explicit pytest paths). Note: `domain.ml` still lives at `packages/domain/src/domain/ml/`. Migrating it would close out the dual-`domain/` layout but is out of scope for this commit. Co-Authored-By: Claude Opus 4.7 --- .../tests/test_summary_pdf_mapper_chain.py | 12 +++--- .../tests/test_building_part_identifier.py | 2 +- docs/adr/0009-deterministic-sap-calculator.md | 8 ++-- ...0-calculator-spec-target-and-validation.md | 12 +++--- docs/sap-spec/HANDOVER_NEXT.md | 28 ++++++------- docs/sap-spec/NEXT_AGENT_PROMPT.md | 8 ++-- docs/sap-spec/SAP_CALCULATOR.md | 24 +++++------ .../sap => domain/sap10_calculator}/README.md | 2 +- domain/{ => sap10_calculator}/__init__.py | 0 .../sap10_calculator}/calculator.py | 16 +++---- .../sap10_calculator/climate}/__init__.py | 0 .../sap10_calculator}/climate/appendix_u.py | 2 +- .../climate/tests}/__init__.py | 0 .../climate/tests/test_appendix_u.py | 2 +- .../sap10_calculator/rdsap}/__init__.py | 0 .../sap10_calculator}/rdsap/cert_to_inputs.py | 42 +++++++++---------- .../sap10_calculator/rdsap/tests}/__init__.py | 0 .../golden/0240-0200-5706-2365-8010.json | 0 .../golden/0300-2747-7640-2526-2135.json | 0 .../golden/0390-2254-6420-2126-5561.json | 0 .../golden/0390-2954-3640-2196-4175.json | 0 .../golden/0535-9020-6509-0821-6222.json | 0 .../golden/2130-1033-4050-5007-8395.json | 0 .../golden/6035-7729-2309-0879-2296.json | 0 .../golden/7536-3827-0600-0600-0276.json | 0 .../golden/8135-1728-8500-0511-3296.json | 0 .../golden/9390-2722-3520-2105-8715.json | 0 .../rdsap/tests/test_cert_to_inputs.py | 10 ++--- .../rdsap/tests/test_golden_fixtures.py | 4 +- .../sap10_calculator/tables}/__init__.py | 0 .../sap10_calculator}/tables/pcdb/__init__.py | 4 +- .../sap10_calculator}/tables/pcdb/etl.py | 6 +-- .../sap10_calculator}/tables/pcdb/parser.py | 0 .../tables/pcdb/postcode_weather.py | 2 +- .../sap10_calculator}/tables/table_12.py | 2 +- .../sap10_calculator}/tables/table_12a.py | 0 .../sap10_calculator}/tables/table_32.py | 4 +- .../sap10_calculator/tests}/__init__.py | 0 .../tests/test_bre_worked_examples.py | 12 +++--- .../tests/test_calculator.py | 12 +++--- .../sap10_calculator}/tests/test_pcdb_etl.py | 6 +-- .../tests/test_pcdb_lookup.py | 2 +- .../tests/test_postcode_weather.py | 2 +- .../sap10_calculator}/tests/test_table_12.py | 2 +- .../sap10_calculator}/tests/test_table_12a.py | 2 +- .../sap10_calculator}/tests/test_table_32.py | 4 +- .../sap10_calculator/validation}/__init__.py | 0 .../validation/parity_report.py | 0 .../validation/tests}/__init__.py | 0 .../validation/tests/test_parity_report.py | 2 +- .../sap10_calculator/worksheet}/__init__.py | 0 .../sap10_calculator}/worksheet/dimensions.py | 0 .../worksheet/energy_requirements.py | 0 .../worksheet/fabric_energy_efficiency.py | 0 .../sap10_calculator}/worksheet/fuel_cost.py | 0 .../worksheet/heat_transmission.py | 2 +- .../worksheet/internal_gains.py | 0 .../worksheet/mean_internal_temperature.py | 2 +- .../sap10_calculator}/worksheet/rating.py | 0 .../worksheet/solar_gains.py | 8 ++-- .../worksheet/space_cooling.py | 0 .../worksheet/space_heating.py | 2 +- .../worksheet/tests}/__init__.py | 0 .../worksheet/tests/_elmhurst_fixtures.py | 2 +- .../tests/_elmhurst_worksheet_000474.py | 8 ++-- .../tests/_elmhurst_worksheet_000477.py | 8 ++-- .../tests/_elmhurst_worksheet_000480.py | 8 ++-- .../tests/_elmhurst_worksheet_000487.py | 8 ++-- .../tests/_elmhurst_worksheet_000490.py | 8 ++-- .../tests/_elmhurst_worksheet_000516.py | 8 ++-- .../tests/_elmhurst_worksheet_001479.py | 0 .../worksheet/tests/_xlsx_loader.py | 4 +- .../basement/0712-3058-2202-3816-8204.json | 0 .../rir/0636-6824-0100-0500-6222.json | 0 .../rir/0636-8125-6600-0416-2202.json | 0 .../rir/0782-3058-6209-9186-1200.json | 0 .../worksheet/tests/test_dimensions.py | 6 +-- .../tests/test_e2e_elmhurst_sap_score.py | 8 ++-- .../tests/test_energy_requirements.py | 2 +- .../tests/test_fabric_energy_efficiency.py | 4 +- .../worksheet/tests/test_fuel_cost.py | 4 +- .../worksheet/tests/test_heat_transmission.py | 8 ++-- .../worksheet/tests/test_internal_gains.py | 6 +-- .../tests/test_mean_internal_temperature.py | 6 +-- .../worksheet/tests/test_rating.py | 2 +- .../tests/test_section_cascade_pins.py | 6 +-- .../worksheet/tests/test_solar_gains.py | 6 +-- .../worksheet/tests/test_space_cooling.py | 6 +-- .../worksheet/tests/test_space_heating.py | 6 +-- .../tests/test_utilisation_factor.py | 2 +- .../worksheet/tests/test_ventilation.py | 8 ++-- .../worksheet/tests/test_water_heating.py | 16 +++---- .../worksheet/utilisation_factor.py | 0 .../worksheet/ventilation.py | 0 .../worksheet/water_heating.py | 0 packages/domain/src/domain/__init__.py | 4 -- packages/domain/src/domain/ml/demand.py | 2 +- .../domain/sap/worksheet/tests/__init__.py | 0 98 files changed, 200 insertions(+), 204 deletions(-) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/README.md (99%) rename domain/{ => sap10_calculator}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/calculator.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator/climate}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/climate/appendix_u.py (99%) rename {packages/domain/src/domain/sap/climate => domain/sap10_calculator/climate/tests}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/climate/tests/test_appendix_u.py (98%) rename {packages/domain/src/domain/sap/climate/tests => domain/sap10_calculator/rdsap}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/cert_to_inputs.py (98%) rename {packages/domain/src/domain/sap/rdsap => domain/sap10_calculator/rdsap/tests}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/0240-0200-5706-2365-8010.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/0300-2747-7640-2526-2135.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/0390-2254-6420-2126-5561.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/0390-2954-3640-2196-4175.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/2130-1033-4050-5007-8395.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/6035-7729-2309-0879-2296.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/7536-3827-0600-0600-0276.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/8135-1728-8500-0511-3296.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/fixtures/golden/9390-2722-3520-2105-8715.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/test_cert_to_inputs.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/rdsap/tests/test_golden_fixtures.py (99%) rename {packages/domain/src/domain/sap/rdsap/tests => domain/sap10_calculator/tables}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/pcdb/__init__.py (96%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/pcdb/etl.py (93%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/pcdb/parser.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/pcdb/postcode_weather.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/table_12.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/table_12a.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tables/table_32.py (98%) rename {packages/domain/src/domain/sap/tables => domain/sap10_calculator/tests}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_bre_worked_examples.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_calculator.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_pcdb_etl.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_pcdb_lookup.py (94%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_postcode_weather.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_table_12.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_table_12a.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/tests/test_table_32.py (98%) rename {packages/domain/src/domain/sap/tests => domain/sap10_calculator/validation}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/validation/parity_report.py (100%) rename {packages/domain/src/domain/sap/validation => domain/sap10_calculator/validation/tests}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/validation/tests/test_parity_report.py (98%) rename {packages/domain/src/domain/sap/validation/tests => domain/sap10_calculator/worksheet}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/dimensions.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/energy_requirements.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/fabric_energy_efficiency.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/fuel_cost.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/heat_transmission.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/internal_gains.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/mean_internal_temperature.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/rating.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/solar_gains.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/space_cooling.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/space_heating.py (98%) rename {packages/domain/src/domain/sap/worksheet => domain/sap10_calculator/worksheet/tests}/__init__.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_fixtures.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000474.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000477.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000480.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000487.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000490.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_000516.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_elmhurst_worksheet_001479.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/_xlsx_loader.py (93%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/fixtures/basement/0712-3058-2202-3816-8204.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/fixtures/rir/0636-6824-0100-0500-6222.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/fixtures/rir/0636-8125-6600-0416-2202.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/fixtures/rir/0782-3058-6209-9186-1200.json (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_dimensions.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_e2e_elmhurst_sap_score.py (96%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_energy_requirements.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_fabric_energy_efficiency.py (91%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_fuel_cost.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_heat_transmission.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_internal_gains.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_mean_internal_temperature.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_rating.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_section_cascade_pins.py (99%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_solar_gains.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_space_cooling.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_space_heating.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_utilisation_factor.py (97%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_ventilation.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/tests/test_water_heating.py (98%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/utilisation_factor.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/ventilation.py (100%) rename {packages/domain/src/domain/sap => domain/sap10_calculator}/worksheet/water_heating.py (100%) delete mode 100644 packages/domain/src/domain/__init__.py delete mode 100644 packages/domain/src/domain/sap/worksheet/tests/__init__.py diff --git a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py index c46964b2..16b621c2 100644 --- a/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py +++ b/backend/documents_parser/tests/test_summary_pdf_mapper_chain.py @@ -1,6 +1,6 @@ """End-to-end validation for the Elmhurst Summary→EpcPropertyData chain. -The 6 Elmhurst worksheet fixtures in `domain.sap.worksheet.tests` +The 6 Elmhurst worksheet fixtures in `domain.sap10_calculator.worksheet.tests` build their `EpcPropertyData` synthetically — they validate the calculator + cascade in isolation from the mapper. This file pins the OTHER half of the chain: `from_elmhurst_site_notes` must produce @@ -37,9 +37,9 @@ from typing import cast from backend.documents_parser.elmhurst_extractor import ElmhurstSiteNotesExtractor from datatypes.epc.domain.mapper import EpcPropertyDataMapper -from domain.sap.calculator import calculate_sap_from_inputs -from domain.sap.rdsap.cert_to_inputs import SAP_10_2_SPEC_PRICES, cert_to_inputs -from domain.sap.worksheet.tests import ( +from domain.sap10_calculator.calculator import calculate_sap_from_inputs +from domain.sap10_calculator.rdsap.cert_to_inputs import SAP_10_2_SPEC_PRICES, cert_to_inputs +from domain.sap10_calculator.worksheet.tests import ( _elmhurst_worksheet_000474 as _w000474, _elmhurst_worksheet_000477 as _w000477, _elmhurst_worksheet_000480 as _w000480, @@ -63,7 +63,7 @@ _SUMMARY_001479_PDF = _FIXTURES / "Summary_001479.pdf" # matches worksheet continuous SAP at 1e-4". _API_001479_JSON = ( Path(__file__).parents[3] - / "packages/domain/src/domain/sap/rdsap/tests/fixtures/golden" + / "domain/sap10_calculator/rdsap/tests/fixtures/golden" / "0535-9020-6509-0821-6222.json" ) @@ -108,7 +108,7 @@ def _summary_pdf_to_textract_style_pages(pdf_path: Path) -> list[str]: def test_summary_000474_mapper_produces_three_building_parts() -> None: # Arrange — cert U985-0001-000474 is a mid-terrace with 3 building # parts (Main + 2 extensions) per the hand-built worksheet fixture - # at packages/domain/src/domain/sap/worksheet/tests/ + # at domain/sap10_calculator/worksheet/tests/ # _elmhurst_worksheet_000474.py. Routing the Summary PDF through # extractor + mapper must yield the same count. pages = _summary_pdf_to_textract_style_pages(_SUMMARY_000474_PDF) diff --git a/datatypes/epc/domain/tests/test_building_part_identifier.py b/datatypes/epc/domain/tests/test_building_part_identifier.py index 3c2f024d..edef68f4 100644 --- a/datatypes/epc/domain/tests/test_building_part_identifier.py +++ b/datatypes/epc/domain/tests/test_building_part_identifier.py @@ -6,7 +6,7 @@ Two boundary factories convert raw inputs to canonical members: - `BuildingPartIdentifier.extension(n)` (site-notes / construction id) P6.1 starts P6 (strict-type EpcPropertyData) from the documented pain -point in packages/domain/src/domain/sap/worksheet/dimensions.py:74-82. +point in domain/sap10_calculator/worksheet/dimensions.py:74-82. """ from __future__ import annotations diff --git a/docs/adr/0009-deterministic-sap-calculator.md b/docs/adr/0009-deterministic-sap-calculator.md index c0c42693..f3f1836a 100644 --- a/docs/adr/0009-deterministic-sap-calculator.md +++ b/docs/adr/0009-deterministic-sap-calculator.md @@ -51,7 +51,7 @@ The ML model is **not deprecated**. It is repurposed as a **residual learner** a A full SAP 10.3 worksheet plus the data-extraction rules from RdSAP 10 Appendix S. Module organisation: ``` -packages/domain/src/domain/sap/ +domain/sap10_calculator/ __init__.py # Sap10Calculator entry point + SapResult dataclass worksheet/ dimensions.py # §1 @@ -79,7 +79,7 @@ packages/domain/src/domain/sap/ 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.sap.*` once parity is reached. +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. ## Sap10Calculator interface @@ -118,7 +118,7 @@ We do **not** retire the existing ML pipeline until both validations pass. - **The six ML targets remain those from ADR-0007.** The residual head predicts deltas against the same six quantities. - **ADR-0008's physics-as-feature pattern stays valid for the ML residual head.** The residual head probably needs fewer features, but the cascade U-value defaults and SAP efficiency lookups remain useful as feature builders if the calculator subset alone underfits. - **`energy_rating_current` remains excluded from features.** Same leakage rule. -- **RdSAP 10 cert-extraction rules are now first-class in the codebase.** Rules that were ad-hoc in `transform.py` move into `domain.sap.rdsap.appendix_s`. +- **RdSAP 10 cert-extraction rules are now first-class in the codebase.** Rules that were ad-hoc in `transform.py` move into `domain.sap10_calculator.rdsap.appendix_s`. - **The training parquet schema continues at v2.x.** A new column `calculator_sap_score` lands as a non-breaking addition once Session A reaches parity. The schema version bumps to v3.0.0 only when the residual targets replace the raw targets — a coordinated AutoGluon-repo deploy, per ADR-0008's cutover discipline. ## SAP 10.2 → SAP 10.3 implications @@ -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.sap.*` 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.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 45fa29bc..7dd52c7c 100644 --- a/docs/adr/0010-sap10-calculator-spec-target-and-validation.md +++ b/docs/adr/0010-sap10-calculator-spec-target-and-validation.md @@ -4,7 +4,7 @@ ## Why this ADR exists -ADR-0009 was written before a second-order problem in the validation corpus was visible: the 250k-cert training parquet spans **multiple SAP spec versions** (SAP 10.1 from 2019, SAP 10.2 pre- and post-14-March-2025 amendment), each of which was the active table when its certs were lodged. The prior session's `domain.sap.tables.table_12_cert_calibration` layer was implicitly absorbing this version mixture into a single "best fit" price set ~10–25 % lower than the SAP 10.2 (14-03-2025) spec — closer to the SAP 10.1 era prices. Every spec-correctness slice that touched a downstream component (HW cylinder zero-loss, gas standing charges, Table 12a fractional blending) registered as a regression on the parity probe because the cert-cal layer had been numerically calibrated against the buggy state of every other component. +ADR-0009 was written before a second-order problem in the validation corpus was visible: the 250k-cert training parquet spans **multiple SAP spec versions** (SAP 10.1 from 2019, SAP 10.2 pre- and post-14-March-2025 amendment), each of which was the active table when its certs were lodged. The prior session's `domain.sap10_calculator.tables.table_12_cert_calibration` layer was implicitly absorbing this version mixture into a single "best fit" price set ~10–25 % lower than the SAP 10.2 (14-03-2025) spec — closer to the SAP 10.1 era prices. Every spec-correctness slice that touched a downstream component (HW cylinder zero-loss, gas standing charges, Table 12a fractional blending) registered as a regression on the parity probe because the cert-cal layer had been numerically calibrated against the buggy state of every other component. This ADR resolves four entangled decisions at once. They are coupled — none of them is the right call in isolation. @@ -14,7 +14,7 @@ This ADR resolves four entangled decisions at once. They are coupled — none of ADR-0009 named SAP 10.3 (13-01-2026) as the calculator's target. No SAP-10.3-lodged certs exist in the corpus; assessor software has not migrated. Targeting SAP 10.3 produces a calculator whose output is verifiable against no cert. The active target is SAP 10.2 (14-03-2025 amendment) — both the document RdSAP 10 (10-06-2025) cross-references for heating-system identification, and the amendment that current assessor software is on. -`packages/domain/src/domain/sap/tables/table_12.py` is re-labelled as SAP 10.2 (14-03-2025). Its CO2 factors are corrected to spec (0.210 kg/kWh mains gas, 0.136 kg/kWh standard electricity — the file currently has SAP 10.3 values 0.214 and 0.086). Prices already match SAP 10.2 (3.64 p mains gas, 16.49 p standard electricity, etc.) — the misleading "+25 % shift from SAP 10.2 to 10.3" comment is removed; the 13.19 p figure is from SAP 10.1, not SAP 10.2. +`domain/sap10_calculator/tables/table_12.py` is re-labelled as SAP 10.2 (14-03-2025). Its CO2 factors are corrected to spec (0.210 kg/kWh mains gas, 0.136 kg/kWh standard electricity — the file currently has SAP 10.3 values 0.214 and 0.086). Prices already match SAP 10.2 (3.64 p mains gas, 16.49 p standard electricity, etc.) — the misleading "+25 % shift from SAP 10.2 to 10.3" comment is removed; the 13.19 p figure is from SAP 10.1, not SAP 10.2. A future ADR retargets to SAP 10.3 once the cert corpus migrates (expected late 2026 or 2027 once BRE updates RdSAP to reference SAP 10.3). @@ -24,7 +24,7 @@ The cert-calibration table is bug-masking. Its prices are pre-March-2025 SAP val This includes the `cert_calibration_e7_codes` extension that routes codes 191–196 (direct-electric) and 691–696 (room heaters) to off-peak rates — Table 12a is explicit that "other direct-acting electric heating" bills 100 % at the high rate on a 7-hour tariff. The S-B14 finding that motivated this hack is in §8 of the handover as a documented dead-end. -`domain.sap.tables.table_12.unit_price_p_per_kwh` becomes the only price API. Parity probes are updated to use it. +`domain.sap10_calculator.tables.table_12.unit_price_p_per_kwh` becomes the only price API. Parity probes are updated to use it. ### 3. Validation Cohort is filtered to a single spec-version window @@ -84,9 +84,9 @@ The 000490 Elmhurst fixture had a recorded -12.5% cost gap (£706 vs £807 PDF) ### Consequences -- **`packages/domain/src/domain/sap/tables/table_32.py`** ships the RdSAP10 unit prices + standing charges + Table 12 note (a) gating function. Table 12 keeps the CO2 + PEF columns. -- **`packages/domain/src/domain/sap/tables/table_12a.py`** ships the high-rate-fraction lookups for off-peak split (Table 12a in SAP 10.2 PDF page 191 — RdSAP10 §19.1 cross-references this table directly). `Tariff.TEN_HOUR` carried for spec completeness even though RdSAP cert `meter_type` enum (1..5) has no 10-hour code. -- **`packages/domain/src/domain/sap/worksheet/fuel_cost.py`** ships the §10a orchestrator producing `FuelCostResult` (32 fields, line refs (240)..(255)). `cert_to_inputs._fuel_cost` precompute wires it from cert state. +- **`domain/sap10_calculator/tables/table_32.py`** ships the RdSAP10 unit prices + standing charges + Table 12 note (a) gating function. Table 12 keeps the CO2 + PEF columns. +- **`domain/sap10_calculator/tables/table_12a.py`** ships the high-rate-fraction lookups for off-peak split (Table 12a in SAP 10.2 PDF page 191 — RdSAP10 §19.1 cross-references this table directly). `Tariff.TEN_HOUR` carried for spec completeness even though RdSAP cert `meter_type` enum (1..5) has no 10-hour code. +- **`domain/sap10_calculator/worksheet/fuel_cost.py`** ships the §10a orchestrator producing `FuelCostResult` (32 fields, line refs (240)..(255)). `cert_to_inputs._fuel_cost` precompute wires it from cert state. - The 000474 Elmhurst fixture cost residual widened from -0.6% to +10.7% (SAP rating ceiling loosened 2 → 4) because the pre-amendment wrong-table-but-cancels-kWh accidentally compensated for upstream §4 HW kWh + Appendix L lighting overestimates. **§4 HW worksheet tightening is the next ticket** — see project memory `project_section_4_hw_next_ticket`. Ceiling drops back to 2 (or below) when that lands. - Golden corpus SAP tolerance widened ±7 → ±11 per the Validation Cohort discipline (oil unit price +55% from Table 12 → Table 32 moves oil-heated golden certs whose lodged SAP scores pre-date Table 32). diff --git a/docs/sap-spec/HANDOVER_NEXT.md b/docs/sap-spec/HANDOVER_NEXT.md index ad4a81aa..b39d1799 100644 --- a/docs/sap-spec/HANDOVER_NEXT.md +++ b/docs/sap-spec/HANDOVER_NEXT.md @@ -41,14 +41,14 @@ plumbing fails loudly. ### Public API (the only thing you need from the SAP module) ```python -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_inputs, # Rating cascade cert_to_demand_inputs, # Demand cascade local_climate_for_cert, environmental_section_from_cert, primary_energy_section_from_cert, ) -from domain.sap.calculator import calculate_sap_from_inputs, SapResult +from domain.sap10_calculator.calculator import calculate_sap_from_inputs, SapResult ``` See `SAP_CALCULATOR.md` §2 for the recommended `dwelling_outputs(epc)` @@ -101,8 +101,8 @@ side is what you need to map out: schema versions (SAP-Schema-18/19, RdSAP-Schema-18) to `EpcPropertyData` lives there. 3. **Is SAP scoring already wired to the API?** Search the backend for - imports of `domain.sap.rdsap.cert_to_inputs` or - `domain.sap.calculator`. If it's not yet wired, the integration test + imports of `domain.sap10_calculator.rdsap.cert_to_inputs` or + `domain.sap10_calculator.calculator`. If it's not yet wired, the integration test is a forcing function for wiring it. 4. **What's the response shape?** The 4 outputs above are what the EPC publishes; the API may already expose them, or may expose a wider @@ -132,10 +132,10 @@ expanding. | File | Why | |---|---| | [`docs/sap-spec/SAP_CALCULATOR.md`](./SAP_CALCULATOR.md) | Module API + architecture (you're heading there) | -| [`packages/domain/src/domain/sap/calculator.py`](../../packages/domain/src/domain/sap/calculator.py) | `SapResult` fields you'll assert against | -| [`packages/domain/src/domain/sap/rdsap/cert_to_inputs.py`](../../packages/domain/src/domain/sap/rdsap/cert_to_inputs.py) | The 3 public entry points + the section helpers | -| [`packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py`](../../packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py) | A reference fixture — `build_epc()` shows the EpcPropertyData shape | -| [`packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py`](../../packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py) | The current e2e test pattern — model your integration test on this | +| [`domain/sap10_calculator/calculator.py`](../../domain/sap10_calculator/calculator.py) | `SapResult` fields you'll assert against | +| [`domain/sap10_calculator/rdsap/cert_to_inputs.py`](../../domain/sap10_calculator/rdsap/cert_to_inputs.py) | The 3 public entry points + the section helpers | +| [`domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py`](../../domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py) | A reference fixture — `build_epc()` shows the EpcPropertyData shape | +| [`domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py`](../../domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py) | The current e2e test pattern — model your integration test on this | | `backend/` (explore) | API entry points | | [`datatypes/epc/domain/mapper.py`](../../datatypes/epc/domain/mapper.py) | Schema → EpcPropertyData mappers | @@ -146,18 +146,18 @@ expanding. ```bash # Confirm SAP calculator is still 930/930 green python -m pytest \ - packages/domain/src/domain/sap/worksheet/tests/test_section_cascade_pins.py \ - packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py \ + domain/sap10_calculator/worksheet/tests/test_section_cascade_pins.py \ + domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \ --no-cov --no-header --tb=no -q # Show the 4 EPC outputs for fixture 000474 cd packages/domain/src && python -c " -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_inputs, local_climate_for_cert, environmental_section_from_cert, primary_energy_section_from_cert, ) -from domain.sap.calculator import calculate_sap_from_inputs -from domain.sap.worksheet.tests import _elmhurst_worksheet_000474 as w +from domain.sap10_calculator.calculator import calculate_sap_from_inputs +from domain.sap10_calculator.worksheet.tests import _elmhurst_worksheet_000474 as w epc = w.build_epc() pc = local_climate_for_cert(epc) rating = calculate_sap_from_inputs(cert_to_inputs(epc)) @@ -183,7 +183,7 @@ postcode-conditions EI value, not what the EPC publishes. - **Extending the SAP calculator.** It's closed at the EPC-output layer. If you find an additional cert-shape variation that breaks the calculator, capture it as a new conformance fixture (see - `packages/domain/src/domain/sap/README.md`) — don't paper over it in + `domain/sap10_calculator/README.md`) — don't paper over it in the integration test. - **BEDF fuel pricing.** The Fuel Bill on the EPC uses postcode-specific BEDF prices (PCDB Table 200), which are deferred. The 4 outputs above diff --git a/docs/sap-spec/NEXT_AGENT_PROMPT.md b/docs/sap-spec/NEXT_AGENT_PROMPT.md index d24f46ca..5b693578 100644 --- a/docs/sap-spec/NEXT_AGENT_PROMPT.md +++ b/docs/sap-spec/NEXT_AGENT_PROMPT.md @@ -111,7 +111,7 @@ from datatypes.epc.domain.mapper import EpcPropertyDataMapper import json, dataclasses from pathlib import Path -api = json.loads(Path('/workspaces/model/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json').read_text()) +api = json.loads(Path('/workspaces/model/domain/sap10_calculator/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json').read_text()) api_mapped = EpcPropertyDataMapper.from_api_response(api) pages = _summary_pdf_to_textract_style_pages(Path('/workspaces/model/backend/documents_parser/tests/fixtures/Summary_001479.pdf')) sn = ElmhurstSiteNotesExtractor(pages).extract() @@ -234,7 +234,7 @@ override field, (c) wait for more cert pairs to confirm pattern. ## Cached artefacts -- `packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0535- +- `domain/sap10_calculator/rdsap/tests/fixtures/golden/0535- 9020-6509-0821-6222.json` — API JSON for cert 001479 (RdSAP-Schema- 21.0.1). - `backend/documents_parser/tests/fixtures/Summary_001479.pdf` — @@ -273,8 +273,8 @@ before this rewrite). ```bash PYTHONPATH=/workspaces/model:/workspaces/model/packages/domain/src \ python -m pytest backend/documents_parser/tests/test_summary_pdf_mapper_chain.py \ - packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py \ - packages/domain/src/domain/sap/rdsap/tests/test_golden_fixtures.py \ + domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \ + domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py \ --no-cov -q ``` Expect **99 passed / 19 failed**. All 19 failures pre-existing: diff --git a/docs/sap-spec/SAP_CALCULATOR.md b/docs/sap-spec/SAP_CALCULATOR.md index be6e6af4..7e6049f5 100644 --- a/docs/sap-spec/SAP_CALCULATOR.md +++ b/docs/sap-spec/SAP_CALCULATOR.md @@ -10,21 +10,21 @@ Current Carbon, Current Primary Energy, and Fuel Bill). **Current state: 930/930 pins green** (768 rating + 90 demand + 72 e2e). This document is the public API + architecture reference. For fixture -authoring see [`packages/domain/src/domain/sap/README.md`](../../packages/domain/src/domain/sap/README.md). +authoring see [`domain/sap10_calculator/README.md`](../../domain/sap10_calculator/README.md). --- ## 1. Public API -Three entry points, all in `domain.sap.rdsap.cert_to_inputs`: +Three entry points, all in `domain.sap10_calculator.rdsap.cert_to_inputs`: ```python -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_inputs, # SAP rating + EI rating (UK-avg climate) cert_to_demand_inputs, # Current Carbon + Current PE (postcode climate) local_climate_for_cert, # postcode → PostcodeClimate (None on miss) ) -from domain.sap.calculator import calculate_sap_from_inputs, SapResult +from domain.sap10_calculator.calculator import calculate_sap_from_inputs, SapResult ``` ### 1.1 Rating cascade — `cert_to_inputs(epc)` @@ -93,11 +93,11 @@ upgrade wall insulation), re-run, observe the delta. The shape: ```python import dataclasses -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_inputs, local_climate_for_cert, environmental_section_from_cert, primary_energy_section_from_cert, ) -from domain.sap.calculator import calculate_sap_from_inputs +from domain.sap10_calculator.calculator import calculate_sap_from_inputs def dwelling_outputs(epc): """The 4 EPC-facing outputs for any cert. @@ -165,7 +165,7 @@ Two cascades stacked on a shared physics core: Climate is the only difference between the two cascades. Internally, the climate is plumbed through as either an `int` region index (0..21) or a `PostcodeClimate` instance (PCDB Table 172). Four functions in -`domain.sap.climate.appendix_u` dispatch on `isinstance`: +`domain.sap10_calculator.climate.appendix_u` dispatch on `isinstance`: `external_temperature_c`, `wind_speed_m_per_s`, `horizontal_solar_irradiance_w_per_m2`, plus `_latitude_deg` in `worksheet/solar_gains.py`. @@ -192,7 +192,7 @@ on `CalculatorInputs`. ## 4. File map ``` -packages/domain/src/domain/sap/ +domain/sap10_calculator/ ├── calculator.py # Top-level orchestrator (CalculatorInputs → SapResult) ├── README.md # Fixture authoring cookbook ├── rdsap/ @@ -288,12 +288,12 @@ monthly_infiltration_ach 6/6 ```bash # Full SAP calculator suite (cascade pins + e2e + helpers) -python -m pytest packages/domain/src/domain/sap/ --no-cov +python -m pytest domain/sap10_calculator/ --no-cov # Cascade pins only (the conformance suite) python -m pytest \ - packages/domain/src/domain/sap/worksheet/tests/test_section_cascade_pins.py \ - packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py \ + domain/sap10_calculator/worksheet/tests/test_section_cascade_pins.py \ + domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py \ --no-cov --no-header --tb=no -q ``` @@ -316,7 +316,7 @@ These are non-negotiable per `[[feedback-zero-error-strict]]` / ## 6. Adding a new conformance fixture -See [`packages/domain/src/domain/sap/README.md#adding-a-new-elmhurst-conformance-fixture`](../../packages/domain/src/domain/sap/README.md#adding-a-new-elmhurst-conformance-fixture) +See [`domain/sap10_calculator/README.md#adding-a-new-elmhurst-conformance-fixture`](../../domain/sap10_calculator/README.md#adding-a-new-elmhurst-conformance-fixture) for the step-by-step cookbook. Summary: 1. Drop a fixture module at `worksheet/tests/_elmhurst_worksheet_NNNNNN.py` diff --git a/packages/domain/src/domain/sap/README.md b/domain/sap10_calculator/README.md similarity index 99% rename from packages/domain/src/domain/sap/README.md rename to domain/sap10_calculator/README.md index 7efd44d3..3beeb5da 100644 --- a/packages/domain/src/domain/sap/README.md +++ b/domain/sap10_calculator/README.md @@ -50,7 +50,7 @@ The assessor exports two PDFs from Elmhurst's RdSAP tool: 5. **Run the conformance tests**: ``` - python -m pytest packages/domain/src/domain/sap/worksheet/tests/ \ + python -m pytest domain/sap10_calculator/worksheet/tests/ \ -k elmhurst --no-cov -v ``` Each fixture appears 3× (one parametrize per section), pytest id = the cert ref number. diff --git a/domain/__init__.py b/domain/sap10_calculator/__init__.py similarity index 100% rename from domain/__init__.py rename to domain/sap10_calculator/__init__.py diff --git a/packages/domain/src/domain/sap/calculator.py b/domain/sap10_calculator/calculator.py similarity index 97% rename from packages/domain/src/domain/sap/calculator.py rename to domain/sap10_calculator/calculator.py index a2385ad6..1cd8cb21 100644 --- a/packages/domain/src/domain/sap/calculator.py +++ b/domain/sap10_calculator/calculator.py @@ -3,7 +3,7 @@ Drives the 12-month heat-balance loop from a typed `CalculatorInputs` aggregate and emits a typed `SapResult`. This module is the physics assembly only — the RdSAP cert→inputs mapping lives in -`domain.sap.rdsap.cert_to_inputs`. Splitting the two keeps orchestration +`domain.sap10_calculator.rdsap.cert_to_inputs`. Splitting the two keeps orchestration testable against synthetic inputs without dragging in cert-shape assumptions. @@ -44,15 +44,15 @@ from __future__ import annotations from dataclasses import dataclass, field from typing import Final, Optional, TYPE_CHECKING -from domain.sap.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.climate.appendix_u import external_temperature_c if TYPE_CHECKING: from datatypes.epc.domain.epc_property_data import EpcPropertyData -from domain.sap.worksheet.dimensions import Dimensions -from domain.sap.worksheet.energy_requirements import EnergyRequirementsResult -from domain.sap.worksheet.fuel_cost import FuelCostResult -from domain.sap.worksheet.heat_transmission import HeatTransmission -from domain.sap.worksheet.rating import ( +from domain.sap10_calculator.worksheet.dimensions import Dimensions +from domain.sap10_calculator.worksheet.energy_requirements import EnergyRequirementsResult +from domain.sap10_calculator.worksheet.fuel_cost import FuelCostResult +from domain.sap10_calculator.worksheet.heat_transmission import HeatTransmission +from domain.sap10_calculator.worksheet.rating import ( ECF_LOG_THRESHOLD, ENERGY_COST_DEFLATOR, FLOOR_AREA_OFFSET_M2, @@ -621,6 +621,6 @@ class Sap10Calculator: """ def calculate(self, epc: "EpcPropertyData") -> SapResult: - from domain.sap.rdsap.cert_to_inputs import cert_to_inputs + from domain.sap10_calculator.rdsap.cert_to_inputs import cert_to_inputs return calculate_sap_from_inputs(cert_to_inputs(epc)) diff --git a/packages/domain/src/domain/sap/__init__.py b/domain/sap10_calculator/climate/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/__init__.py rename to domain/sap10_calculator/climate/__init__.py diff --git a/packages/domain/src/domain/sap/climate/appendix_u.py b/domain/sap10_calculator/climate/appendix_u.py similarity index 99% rename from packages/domain/src/domain/sap/climate/appendix_u.py rename to domain/sap10_calculator/climate/appendix_u.py index b3cc922d..8db42d16 100644 --- a/packages/domain/src/domain/sap/climate/appendix_u.py +++ b/domain/sap10_calculator/climate/appendix_u.py @@ -20,7 +20,7 @@ from __future__ import annotations from typing import Final -from domain.sap.tables.pcdb.postcode_weather import PostcodeClimate +from domain.sap10_calculator.tables.pcdb.postcode_weather import PostcodeClimate # Table U1 — Mean external temperature (°C), 22 regions × 12 months. diff --git a/packages/domain/src/domain/sap/climate/__init__.py b/domain/sap10_calculator/climate/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/climate/__init__.py rename to domain/sap10_calculator/climate/tests/__init__.py diff --git a/packages/domain/src/domain/sap/climate/tests/test_appendix_u.py b/domain/sap10_calculator/climate/tests/test_appendix_u.py similarity index 98% rename from packages/domain/src/domain/sap/climate/tests/test_appendix_u.py rename to domain/sap10_calculator/climate/tests/test_appendix_u.py index aba5a8a9..8777d161 100644 --- a/packages/domain/src/domain/sap/climate/tests/test_appendix_u.py +++ b/domain/sap10_calculator/climate/tests/test_appendix_u.py @@ -8,7 +8,7 @@ global solar irradiance on a horizontal plane and monthly solar declination. import pytest -from domain.sap.climate.appendix_u import ( +from domain.sap10_calculator.climate.appendix_u import ( external_temperature_c, horizontal_solar_irradiance_w_per_m2, solar_declination_deg, diff --git a/packages/domain/src/domain/sap/climate/tests/__init__.py b/domain/sap10_calculator/rdsap/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/climate/tests/__init__.py rename to domain/sap10_calculator/rdsap/__init__.py diff --git a/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py b/domain/sap10_calculator/rdsap/cert_to_inputs.py similarity index 98% rename from packages/domain/src/domain/sap/rdsap/cert_to_inputs.py rename to domain/sap10_calculator/rdsap/cert_to_inputs.py index 581a303d..ed5858c3 100644 --- a/packages/domain/src/domain/sap/rdsap/cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/cert_to_inputs.py @@ -67,82 +67,82 @@ from domain.ml.sap_efficiencies import ( seasonal_efficiency, water_heating_efficiency as _legacy_water_heating_efficiency, ) -from domain.sap.calculator import CalculatorInputs -from domain.sap.tables.pcdb import gas_oil_boiler_record -from domain.sap.tables.pcdb.parser import GasOilBoilerRecord -from domain.sap.tables.pcdb.postcode_weather import ( +from domain.sap10_calculator.calculator import CalculatorInputs +from domain.sap10_calculator.tables.pcdb import gas_oil_boiler_record +from domain.sap10_calculator.tables.pcdb.parser import GasOilBoilerRecord +from domain.sap10_calculator.tables.pcdb.postcode_weather import ( PostcodeClimate, postcode_climate, ) -from domain.sap.tables.table_12 import ( +from domain.sap10_calculator.tables.table_12 import ( co2_monthly_factors_kg_per_kwh, co2_factor_kg_per_kwh, pe_monthly_factors_kwh_per_kwh, primary_energy_factor, unit_price_p_per_kwh, ) -from domain.sap.tables.table_12a import ( +from domain.sap10_calculator.tables.table_12a import ( Tariff, tariff_from_meter_type, ) -from domain.sap.tables.table_32 import ( +from domain.sap10_calculator.tables.table_32 import ( additional_standing_charges_gbp, unit_price_p_per_kwh as table_32_unit_price_p_per_kwh, ) -from domain.sap.worksheet.fuel_cost import FuelCostResult, fuel_cost -from domain.sap.worksheet.rating import ( +from domain.sap10_calculator.worksheet.fuel_cost import FuelCostResult, fuel_cost +from domain.sap10_calculator.worksheet.rating import ( ENERGY_COST_DEFLATOR, energy_cost_factor, environmental_impact_rating, sap_rating, sap_rating_integer, ) -from domain.sap.worksheet.dimensions import dimensions_from_cert -from domain.sap.worksheet.internal_gains import ( +from domain.sap10_calculator.worksheet.dimensions import dimensions_from_cert +from domain.sap10_calculator.worksheet.internal_gains import ( InternalGainsResult, OvershadingCategory, internal_gains_from_cert, ) -from domain.sap.worksheet.solar_gains import ( +from domain.sap10_calculator.worksheet.solar_gains import ( ORIENTATION_BY_SAP10_CODE, RoofWindowInput, SolarGainsResult, solar_gains_from_cert, surface_solar_flux_w_per_m2, ) -from domain.sap.worksheet.heat_transmission import ( +from domain.sap10_calculator.worksheet.heat_transmission import ( DwellingExposure, HeatTransmission, _AREA_ROUND_DP, _round_half_up, heat_transmission_from_cert, ) -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.mean_internal_temperature import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.mean_internal_temperature import ( MeanInternalTemperatureResult, mean_internal_temperature_monthly, ) -from domain.sap.worksheet.energy_requirements import ( +from domain.sap10_calculator.worksheet.energy_requirements import ( EnergyRequirementsResult, space_heating_fuel_monthly_kwh, ) -from domain.sap.worksheet.fabric_energy_efficiency import ( +from domain.sap10_calculator.worksheet.fabric_energy_efficiency import ( fabric_energy_efficiency_kwh_per_m2_yr, ) -from domain.sap.worksheet.space_cooling import ( +from domain.sap10_calculator.worksheet.space_cooling import ( SpaceCoolingResult, space_cooling_monthly_kwh, ) -from domain.sap.worksheet.space_heating import ( +from domain.sap10_calculator.worksheet.space_heating import ( SpaceHeatingResult, space_heating_monthly_kwh, ) -from domain.sap.worksheet.ventilation import ( +from domain.sap10_calculator.worksheet.ventilation import ( MechanicalVentilationKind, VentilationResult, ventilation_from_inputs, ) -from domain.sap.worksheet.water_heating import ( +from domain.sap10_calculator.worksheet.water_heating import ( TABLE_J1_TCOLD_FROM_MAINS_C, WaterHeatingResult, combi_loss_monthly_kwh_table_3b_row_1_instantaneous, diff --git a/packages/domain/src/domain/sap/rdsap/__init__.py b/domain/sap10_calculator/rdsap/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/rdsap/__init__.py rename to domain/sap10_calculator/rdsap/tests/__init__.py diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0240-0200-5706-2365-8010.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/0240-0200-5706-2365-8010.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0240-0200-5706-2365-8010.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/0240-0200-5706-2365-8010.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0300-2747-7640-2526-2135.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/0300-2747-7640-2526-2135.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0300-2747-7640-2526-2135.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/0300-2747-7640-2526-2135.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0390-2254-6420-2126-5561.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/0390-2254-6420-2126-5561.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0390-2254-6420-2126-5561.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/0390-2254-6420-2126-5561.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0390-2954-3640-2196-4175.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/0390-2954-3640-2196-4175.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0390-2954-3640-2196-4175.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/0390-2954-3640-2196-4175.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/0535-9020-6509-0821-6222.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/2130-1033-4050-5007-8395.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/2130-1033-4050-5007-8395.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/2130-1033-4050-5007-8395.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/2130-1033-4050-5007-8395.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/6035-7729-2309-0879-2296.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/6035-7729-2309-0879-2296.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/6035-7729-2309-0879-2296.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/6035-7729-2309-0879-2296.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/7536-3827-0600-0600-0276.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/7536-3827-0600-0600-0276.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/7536-3827-0600-0600-0276.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/7536-3827-0600-0600-0276.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/8135-1728-8500-0511-3296.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/8135-1728-8500-0511-3296.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/8135-1728-8500-0511-3296.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/8135-1728-8500-0511-3296.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/9390-2722-3520-2105-8715.json b/domain/sap10_calculator/rdsap/tests/fixtures/golden/9390-2722-3520-2105-8715.json similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/fixtures/golden/9390-2722-3520-2105-8715.json rename to domain/sap10_calculator/rdsap/tests/fixtures/golden/9390-2722-3520-2105-8715.json diff --git a/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py b/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py similarity index 99% rename from packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py rename to domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py index a4a3c38f..8b0553ae 100644 --- a/packages/domain/src/domain/sap/rdsap/tests/test_cert_to_inputs.py +++ b/domain/sap10_calculator/rdsap/tests/test_cert_to_inputs.py @@ -27,15 +27,15 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.calculator import Sap10Calculator, SapResult -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.calculator import Sap10Calculator, SapResult +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_demand_inputs, cert_to_inputs, pcdb_combi_loss_override, ) -from domain.sap.tables.pcdb import GasOilBoilerRecord, gas_oil_boiler_record -from domain.sap.worksheet.tests import _elmhurst_worksheet_000477 as _w000477 -from domain.sap.worksheet.water_heating import ( +from domain.sap10_calculator.tables.pcdb import GasOilBoilerRecord, gas_oil_boiler_record +from domain.sap10_calculator.worksheet.tests import _elmhurst_worksheet_000477 as _w000477 +from domain.sap10_calculator.worksheet.water_heating import ( combi_loss_monthly_kwh_table_3b_row_1_instantaneous, combi_loss_monthly_kwh_table_3c_two_profile_instantaneous, ) diff --git a/packages/domain/src/domain/sap/rdsap/tests/test_golden_fixtures.py b/domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py similarity index 99% rename from packages/domain/src/domain/sap/rdsap/tests/test_golden_fixtures.py rename to domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py index 9ee7d722..0e6d682c 100644 --- a/packages/domain/src/domain/sap/rdsap/tests/test_golden_fixtures.py +++ b/domain/sap10_calculator/rdsap/tests/test_golden_fixtures.py @@ -36,8 +36,8 @@ from typing import Any import pytest from datatypes.epc.domain.mapper import EpcPropertyDataMapper -from domain.sap.calculator import calculate_sap_from_inputs -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.calculator import calculate_sap_from_inputs +from domain.sap10_calculator.rdsap.cert_to_inputs import ( SAP_10_2_SPEC_PRICES, cert_to_demand_inputs, cert_to_inputs, diff --git a/packages/domain/src/domain/sap/rdsap/tests/__init__.py b/domain/sap10_calculator/tables/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/rdsap/tests/__init__.py rename to domain/sap10_calculator/tables/__init__.py diff --git a/packages/domain/src/domain/sap/tables/pcdb/__init__.py b/domain/sap10_calculator/tables/pcdb/__init__.py similarity index 96% rename from packages/domain/src/domain/sap/tables/pcdb/__init__.py rename to domain/sap10_calculator/tables/pcdb/__init__.py index b9c06a79..a1939712 100644 --- a/packages/domain/src/domain/sap/tables/pcdb/__init__.py +++ b/domain/sap10_calculator/tables/pcdb/__init__.py @@ -27,13 +27,13 @@ import json from pathlib import Path from typing import Final, Optional -from domain.sap.tables.pcdb.parser import GasOilBoilerRecord +from domain.sap10_calculator.tables.pcdb.parser import GasOilBoilerRecord __all__ = ["GasOilBoilerRecord", "gas_oil_boiler_record"] _REPO_SAP_SPEC_DIR: Final[Path] = ( - Path(__file__).resolve().parents[7] / "docs" / "sap-spec" + Path(__file__).resolve().parents[4] / "docs" / "sap-spec" ) _TABLE_105_JSONL: Final[Path] = ( _REPO_SAP_SPEC_DIR / "pcdb_table_105_gas_oil_boilers.jsonl" diff --git a/packages/domain/src/domain/sap/tables/pcdb/etl.py b/domain/sap10_calculator/tables/pcdb/etl.py similarity index 93% rename from packages/domain/src/domain/sap/tables/pcdb/etl.py rename to domain/sap10_calculator/tables/pcdb/etl.py index 37bcfb27..85dc6df6 100644 --- a/packages/domain/src/domain/sap/tables/pcdb/etl.py +++ b/domain/sap10_calculator/tables/pcdb/etl.py @@ -2,7 +2,7 @@ Idempotent. Re-run when BRE publishes an updated pcdb10.dat. JSON files are committed in-repo alongside the source .dat so callers can load -without a build step. Run via `python -m domain.sap.tables.pcdb.etl`. +without a build step. Run via `python -m domain.sap10_calculator.tables.pcdb.etl`. Reference: BRE PCDB pcdb10.dat (April 2026 revision). """ @@ -13,7 +13,7 @@ import json from dataclasses import asdict from pathlib import Path -from domain.sap.tables.pcdb.parser import ( +from domain.sap10_calculator.tables.pcdb.parser import ( GasOilBoilerRecord, RawPcdbRecord, parse_table_105, @@ -75,7 +75,7 @@ def run_etl(*, source: Path, output_dir: Path) -> None: if __name__ == "__main__": # pragma: no cover — manual ETL invocation - repo_root = Path(__file__).resolve().parents[7] + repo_root = Path(__file__).resolve().parents[4] run_etl( source=repo_root / "docs" / "sap-spec" / "pcdb10.dat", output_dir=repo_root / "docs" / "sap-spec", diff --git a/packages/domain/src/domain/sap/tables/pcdb/parser.py b/domain/sap10_calculator/tables/pcdb/parser.py similarity index 100% rename from packages/domain/src/domain/sap/tables/pcdb/parser.py rename to domain/sap10_calculator/tables/pcdb/parser.py diff --git a/packages/domain/src/domain/sap/tables/pcdb/postcode_weather.py b/domain/sap10_calculator/tables/pcdb/postcode_weather.py similarity index 98% rename from packages/domain/src/domain/sap/tables/pcdb/postcode_weather.py rename to domain/sap10_calculator/tables/pcdb/postcode_weather.py index 90622b4d..b808bbf8 100644 --- a/packages/domain/src/domain/sap/tables/pcdb/postcode_weather.py +++ b/domain/sap10_calculator/tables/pcdb/postcode_weather.py @@ -21,7 +21,7 @@ from typing import Final, Optional _PCDB_DAT_PATH: Final[Path] = ( - Path(__file__).resolve().parents[7] / "docs" / "sap-spec" / "pcdb10.dat" + Path(__file__).resolve().parents[4] / "docs" / "sap-spec" / "pcdb10.dat" ) _TABLE_172_TAG: Final[str] = "$172" diff --git a/packages/domain/src/domain/sap/tables/table_12.py b/domain/sap10_calculator/tables/table_12.py similarity index 99% rename from packages/domain/src/domain/sap/tables/table_12.py rename to domain/sap10_calculator/tables/table_12.py index 78c55488..8b83ddbc 100644 --- a/packages/domain/src/domain/sap/tables/table_12.py +++ b/domain/sap10_calculator/tables/table_12.py @@ -14,7 +14,7 @@ factors are largely unchanged. When the corpus migrates to SAP 10.3 this module re-points to those values. The Energy Cost Deflator stays at 0.36 (used in ECF — see -`domain.sap.worksheet.rating`). +`domain.sap10_calculator.worksheet.rating`). """ from __future__ import annotations diff --git a/packages/domain/src/domain/sap/tables/table_12a.py b/domain/sap10_calculator/tables/table_12a.py similarity index 100% rename from packages/domain/src/domain/sap/tables/table_12a.py rename to domain/sap10_calculator/tables/table_12a.py diff --git a/packages/domain/src/domain/sap/tables/table_32.py b/domain/sap10_calculator/tables/table_32.py similarity index 98% rename from packages/domain/src/domain/sap/tables/table_32.py rename to domain/sap10_calculator/tables/table_32.py index c205bba8..b063e23a 100644 --- a/packages/domain/src/domain/sap/tables/table_32.py +++ b/domain/sap10_calculator/tables/table_32.py @@ -7,14 +7,14 @@ targets RdSAP10 cost per ADR-0010 amendment. CO2 emission factors and primary energy factors are unchanged from SAP10.2 Table 12 (RdSAP10 §19.2), so they continue to live in -`domain.sap.tables.table_12` rather than being duplicated here. +`domain.sap10_calculator.tables.table_12` rather than being duplicated here. """ from __future__ import annotations from typing import Final, Optional -from domain.sap.tables.table_12a import Tariff +from domain.sap10_calculator.tables.table_12a import Tariff _DEFAULT_P_PER_KWH: Final[float] = 3.48 # fall back to mains gas diff --git a/packages/domain/src/domain/sap/tables/__init__.py b/domain/sap10_calculator/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/tables/__init__.py rename to domain/sap10_calculator/tests/__init__.py diff --git a/packages/domain/src/domain/sap/tests/test_bre_worked_examples.py b/domain/sap10_calculator/tests/test_bre_worked_examples.py similarity index 97% rename from packages/domain/src/domain/sap/tests/test_bre_worked_examples.py rename to domain/sap10_calculator/tests/test_bre_worked_examples.py index b96bce6a..3166856d 100644 --- a/packages/domain/src/domain/sap/tests/test_bre_worked_examples.py +++ b/domain/sap10_calculator/tests/test_bre_worked_examples.py @@ -23,17 +23,17 @@ from __future__ import annotations import pytest -from domain.sap.calculator import ( +from domain.sap10_calculator.calculator import ( CalculatorInputs, calculate_sap_from_inputs, ) -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.dimensions import Dimensions -from domain.sap.worksheet.heat_transmission import HeatTransmission -from domain.sap.worksheet.mean_internal_temperature import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.dimensions import Dimensions +from domain.sap10_calculator.worksheet.heat_transmission import HeatTransmission +from domain.sap10_calculator.worksheet.mean_internal_temperature import ( mean_internal_temperature_monthly, ) -from domain.sap.worksheet.space_heating import space_heating_monthly_kwh +from domain.sap10_calculator.worksheet.space_heating import space_heating_monthly_kwh def _baseline_dwelling() -> CalculatorInputs: diff --git a/packages/domain/src/domain/sap/tests/test_calculator.py b/domain/sap10_calculator/tests/test_calculator.py similarity index 98% rename from packages/domain/src/domain/sap/tests/test_calculator.py rename to domain/sap10_calculator/tests/test_calculator.py index b6c61f65..0cc47d84 100644 --- a/packages/domain/src/domain/sap/tests/test_calculator.py +++ b/domain/sap10_calculator/tests/test_calculator.py @@ -20,18 +20,18 @@ from dataclasses import replace import pytest -from domain.sap.calculator import ( +from domain.sap10_calculator.calculator import ( CalculatorInputs, SapResult, calculate_sap_from_inputs, ) -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.dimensions import Dimensions -from domain.sap.worksheet.heat_transmission import HeatTransmission -from domain.sap.worksheet.mean_internal_temperature import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.dimensions import Dimensions +from domain.sap10_calculator.worksheet.heat_transmission import HeatTransmission +from domain.sap10_calculator.worksheet.mean_internal_temperature import ( mean_internal_temperature_monthly, ) -from domain.sap.worksheet.space_heating import space_heating_monthly_kwh +from domain.sap10_calculator.worksheet.space_heating import space_heating_monthly_kwh def _baseline_inputs() -> CalculatorInputs: diff --git a/packages/domain/src/domain/sap/tests/test_pcdb_etl.py b/domain/sap10_calculator/tests/test_pcdb_etl.py similarity index 98% rename from packages/domain/src/domain/sap/tests/test_pcdb_etl.py rename to domain/sap10_calculator/tests/test_pcdb_etl.py index 71b57a0f..87d0957e 100644 --- a/packages/domain/src/domain/sap/tests/test_pcdb_etl.py +++ b/domain/sap10_calculator/tests/test_pcdb_etl.py @@ -15,15 +15,15 @@ from pathlib import Path import pytest -from domain.sap.tables.pcdb.etl import run_etl -from domain.sap.tables.pcdb.parser import ( +from domain.sap10_calculator.tables.pcdb.etl import run_etl +from domain.sap10_calculator.tables.pcdb.parser import ( parse_table_105, parse_table_105_row, parse_table_raw, ) -_REPO_ROOT: Path = Path(__file__).resolve().parents[6] +_REPO_ROOT: Path = Path(__file__).resolve().parents[3] _PCDB_DAT_PATH: Path = _REPO_ROOT / "docs" / "sap-spec" / "pcdb10.dat" diff --git a/packages/domain/src/domain/sap/tests/test_pcdb_lookup.py b/domain/sap10_calculator/tests/test_pcdb_lookup.py similarity index 94% rename from packages/domain/src/domain/sap/tests/test_pcdb_lookup.py rename to domain/sap10_calculator/tests/test_pcdb_lookup.py index 742debfe..e2d28959 100644 --- a/packages/domain/src/domain/sap/tests/test_pcdb_lookup.py +++ b/domain/sap10_calculator/tests/test_pcdb_lookup.py @@ -10,7 +10,7 @@ Reference: BRE PCDB pcdb10.dat (April 2026); user-verified records. from __future__ import annotations -from domain.sap.tables.pcdb import gas_oil_boiler_record +from domain.sap10_calculator.tables.pcdb import gas_oil_boiler_record def test_gas_oil_boiler_record_returns_verified_baxi_98() -> None: diff --git a/packages/domain/src/domain/sap/tests/test_postcode_weather.py b/domain/sap10_calculator/tests/test_postcode_weather.py similarity index 97% rename from packages/domain/src/domain/sap/tests/test_postcode_weather.py rename to domain/sap10_calculator/tests/test_postcode_weather.py index 2179c534..0a09af29 100644 --- a/packages/domain/src/domain/sap/tests/test_postcode_weather.py +++ b/domain/sap10_calculator/tests/test_postcode_weather.py @@ -10,7 +10,7 @@ Reference: BRE PCDB pcdb10.dat Table 172 (Postcodes). """ from __future__ import annotations -from domain.sap.tables.pcdb.postcode_weather import ( +from domain.sap10_calculator.tables.pcdb.postcode_weather import ( PostcodeClimate, postcode_climate, ) diff --git a/packages/domain/src/domain/sap/tests/test_table_12.py b/domain/sap10_calculator/tests/test_table_12.py similarity index 98% rename from packages/domain/src/domain/sap/tests/test_table_12.py rename to domain/sap10_calculator/tests/test_table_12.py index 5f133c5a..c611a6b3 100644 --- a/packages/domain/src/domain/sap/tests/test_table_12.py +++ b/domain/sap10_calculator/tests/test_table_12.py @@ -15,7 +15,7 @@ from __future__ import annotations import pytest -from domain.sap.tables.table_12 import ( +from domain.sap10_calculator.tables.table_12 import ( co2_factor_kg_per_kwh, primary_energy_factor, unit_price_p_per_kwh, diff --git a/packages/domain/src/domain/sap/tests/test_table_12a.py b/domain/sap10_calculator/tests/test_table_12a.py similarity index 99% rename from packages/domain/src/domain/sap/tests/test_table_12a.py rename to domain/sap10_calculator/tests/test_table_12a.py index 9208f202..1811d5e4 100644 --- a/packages/domain/src/domain/sap/tests/test_table_12a.py +++ b/domain/sap10_calculator/tests/test_table_12a.py @@ -12,7 +12,7 @@ from __future__ import annotations import pytest -from domain.sap.tables.table_12a import ( +from domain.sap10_calculator.tables.table_12a import ( OtherUse, Table12aSystem, Tariff, diff --git a/packages/domain/src/domain/sap/tests/test_table_32.py b/domain/sap10_calculator/tests/test_table_32.py similarity index 98% rename from packages/domain/src/domain/sap/tests/test_table_32.py rename to domain/sap10_calculator/tests/test_table_32.py index e1689177..f44328d0 100644 --- a/packages/domain/src/domain/sap/tests/test_table_32.py +++ b/domain/sap10_calculator/tests/test_table_32.py @@ -13,8 +13,8 @@ from __future__ import annotations import pytest -from domain.sap.tables.table_12a import Tariff -from domain.sap.tables.table_32 import ( +from domain.sap10_calculator.tables.table_12a import Tariff +from domain.sap10_calculator.tables.table_32 import ( additional_standing_charges_gbp, standing_charge_gbp, unit_price_p_per_kwh, diff --git a/packages/domain/src/domain/sap/tests/__init__.py b/domain/sap10_calculator/validation/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/tests/__init__.py rename to domain/sap10_calculator/validation/__init__.py diff --git a/packages/domain/src/domain/sap/validation/parity_report.py b/domain/sap10_calculator/validation/parity_report.py similarity index 100% rename from packages/domain/src/domain/sap/validation/parity_report.py rename to domain/sap10_calculator/validation/parity_report.py diff --git a/packages/domain/src/domain/sap/validation/__init__.py b/domain/sap10_calculator/validation/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/validation/__init__.py rename to domain/sap10_calculator/validation/tests/__init__.py diff --git a/packages/domain/src/domain/sap/validation/tests/test_parity_report.py b/domain/sap10_calculator/validation/tests/test_parity_report.py similarity index 98% rename from packages/domain/src/domain/sap/validation/tests/test_parity_report.py rename to domain/sap10_calculator/validation/tests/test_parity_report.py index cb987c45..0121902f 100644 --- a/packages/domain/src/domain/sap/validation/tests/test_parity_report.py +++ b/domain/sap10_calculator/validation/tests/test_parity_report.py @@ -15,7 +15,7 @@ from __future__ import annotations import pytest -from domain.sap.validation.parity_report import ( +from domain.sap10_calculator.validation.parity_report import ( ParityCase, ParityReport, build_parity_report, diff --git a/packages/domain/src/domain/sap/validation/tests/__init__.py b/domain/sap10_calculator/worksheet/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/validation/tests/__init__.py rename to domain/sap10_calculator/worksheet/__init__.py diff --git a/packages/domain/src/domain/sap/worksheet/dimensions.py b/domain/sap10_calculator/worksheet/dimensions.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/dimensions.py rename to domain/sap10_calculator/worksheet/dimensions.py diff --git a/packages/domain/src/domain/sap/worksheet/energy_requirements.py b/domain/sap10_calculator/worksheet/energy_requirements.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/energy_requirements.py rename to domain/sap10_calculator/worksheet/energy_requirements.py diff --git a/packages/domain/src/domain/sap/worksheet/fabric_energy_efficiency.py b/domain/sap10_calculator/worksheet/fabric_energy_efficiency.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/fabric_energy_efficiency.py rename to domain/sap10_calculator/worksheet/fabric_energy_efficiency.py diff --git a/packages/domain/src/domain/sap/worksheet/fuel_cost.py b/domain/sap10_calculator/worksheet/fuel_cost.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/fuel_cost.py rename to domain/sap10_calculator/worksheet/fuel_cost.py diff --git a/packages/domain/src/domain/sap/worksheet/heat_transmission.py b/domain/sap10_calculator/worksheet/heat_transmission.py similarity index 99% rename from packages/domain/src/domain/sap/worksheet/heat_transmission.py rename to domain/sap10_calculator/worksheet/heat_transmission.py index 0ec63012..e6bc2572 100644 --- a/packages/domain/src/domain/sap/worksheet/heat_transmission.py +++ b/domain/sap10_calculator/worksheet/heat_transmission.py @@ -30,7 +30,7 @@ will retire envelope.py in favour of this module (ADR-0009 §"Module layout"). U-value lookups cascade through `domain.ml.rdsap_uvalues` — migrating to -`domain.sap.rdsap.cascade_defaults` in Session B. +`domain.sap10_calculator.rdsap.cascade_defaults` in Session B. Reference: SAP 10.2 specification §3 (pages 17-22); RdSAP 10 §5 (Tables 6-24); xlsx worked example at `2026-05-19-17-18 RdSap10Worksheet.xlsx`, diff --git a/packages/domain/src/domain/sap/worksheet/internal_gains.py b/domain/sap10_calculator/worksheet/internal_gains.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/internal_gains.py rename to domain/sap10_calculator/worksheet/internal_gains.py diff --git a/packages/domain/src/domain/sap/worksheet/mean_internal_temperature.py b/domain/sap10_calculator/worksheet/mean_internal_temperature.py similarity index 99% rename from packages/domain/src/domain/sap/worksheet/mean_internal_temperature.py rename to domain/sap10_calculator/worksheet/mean_internal_temperature.py index 8e3be03d..cddd8a08 100644 --- a/packages/domain/src/domain/sap/worksheet/mean_internal_temperature.py +++ b/domain/sap10_calculator/worksheet/mean_internal_temperature.py @@ -23,7 +23,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import Final -from domain.sap.worksheet.utilisation_factor import utilisation_factor +from domain.sap10_calculator.worksheet.utilisation_factor import utilisation_factor _T_H1_C: Final[float] = 21.0 diff --git a/packages/domain/src/domain/sap/worksheet/rating.py b/domain/sap10_calculator/worksheet/rating.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/rating.py rename to domain/sap10_calculator/worksheet/rating.py diff --git a/packages/domain/src/domain/sap/worksheet/solar_gains.py b/domain/sap10_calculator/worksheet/solar_gains.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/solar_gains.py rename to domain/sap10_calculator/worksheet/solar_gains.py index 66af6e98..8e94e9c5 100644 --- a/packages/domain/src/domain/sap/worksheet/solar_gains.py +++ b/domain/sap10_calculator/worksheet/solar_gains.py @@ -6,7 +6,7 @@ Two layers: implements the §U3.2 polynomial that converts the horizontal solar irradiance from Table U3 into a per-orientation per-pitch surface flux. Reads: - - S_h,m from Appendix U Table U3 (already in `domain.sap.climate.appendix_u`) + - S_h,m from Appendix U Table U3 (already in `domain.sap10_calculator.climate.appendix_u`) - δ from Appendix U Table U3 footer (already in `appendix_u.solar_declination_deg`) - φ from Appendix U Table U4 (this module) - k1..k9 from Appendix U Table U5 (this module) @@ -35,12 +35,12 @@ from math import cos, floor, radians, sin from typing import Final from datatypes.epc.domain.epc_property_data import EpcPropertyData, SapWindow -from domain.sap.tables.pcdb.postcode_weather import PostcodeClimate -from domain.sap.climate.appendix_u import ( +from domain.sap10_calculator.tables.pcdb.postcode_weather import PostcodeClimate +from domain.sap10_calculator.climate.appendix_u import ( horizontal_solar_irradiance_w_per_m2, solar_declination_deg, ) -from domain.sap.worksheet.internal_gains import OvershadingCategory +from domain.sap10_calculator.worksheet.internal_gains import OvershadingCategory def _round_area_2dp(value: float) -> float: diff --git a/packages/domain/src/domain/sap/worksheet/space_cooling.py b/domain/sap10_calculator/worksheet/space_cooling.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/space_cooling.py rename to domain/sap10_calculator/worksheet/space_cooling.py diff --git a/packages/domain/src/domain/sap/worksheet/space_heating.py b/domain/sap10_calculator/worksheet/space_heating.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/space_heating.py rename to domain/sap10_calculator/worksheet/space_heating.py index 38a31156..5e747b8a 100644 --- a/packages/domain/src/domain/sap/worksheet/space_heating.py +++ b/domain/sap10_calculator/worksheet/space_heating.py @@ -18,7 +18,7 @@ from __future__ import annotations from dataclasses import dataclass from typing import Final -from domain.sap.worksheet.heat_transmission import _round_half_up +from domain.sap10_calculator.worksheet.heat_transmission import _round_half_up _MIN_KWH_PER_MONTH: Final[float] = 1.0 diff --git a/packages/domain/src/domain/sap/worksheet/__init__.py b/domain/sap10_calculator/worksheet/tests/__init__.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/__init__.py rename to domain/sap10_calculator/worksheet/tests/__init__.py diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_fixtures.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_fixtures.py similarity index 97% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_fixtures.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_fixtures.py index 45d8d538..51b48950 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_fixtures.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_fixtures.py @@ -24,7 +24,7 @@ SECTION_8C_INTERMITTENCY_MONTHLY: tuple[float, ...] = ( 0.0, 0.0, 0.0, 0.0, 0.0, 0.25, 0.25, 0.25, 0.0, 0.0, 0.0, 0.0, ) -from domain.sap.worksheet.tests import ( +from domain.sap10_calculator.worksheet.tests import ( _elmhurst_worksheet_000474 as w000474, _elmhurst_worksheet_000477 as w000477, _elmhurst_worksheet_000480 as w000480, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py index 970cbf90..8a0012a5 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000474.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000474.py @@ -37,11 +37,11 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import RoofWindowInput, RooflightInput -from domain.sap.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000477.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000477.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py index 12242237..446e1f90 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000477.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000477.py @@ -35,11 +35,11 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import RoofWindowInput, RooflightInput -from domain.sap.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000480.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000480.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py index 24724997..d3ebd2e6 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000480.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000480.py @@ -36,11 +36,11 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import RoofWindowInput, RooflightInput -from domain.sap.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py index 2ba0d166..32ebc83d 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000487.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000487.py @@ -34,8 +34,8 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import RoofWindowInput, RooflightInput -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C # RdSAP wall_construction code seen in the cert→worksheet mapping. The # Summary lists "CA Cavity" for both main and extension walls. The alt @@ -258,9 +258,9 @@ def build_epc() -> EpcPropertyData: # on the EpcPropertyData domain object — we pass these into # `ventilation_from_inputs` alongside the cert-derived geometry). # ============================================================================ -from domain.sap.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py index 54daf497..039eb534 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000490.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000490.py @@ -39,11 +39,11 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import RoofWindowInput, RooflightInput -from domain.sap.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000516.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000516.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py index 3848264d..82ff058f 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_000516.py +++ b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_000516.py @@ -42,11 +42,11 @@ from domain.ml.tests._fixtures import ( make_sap_heating, make_window, ) -from domain.sap.worksheet.solar_gains import Orientation, RoofWindowInput, RooflightInput -from domain.sap.worksheet.ventilation import MechanicalVentilationKind -from domain.sap.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C +from domain.sap10_calculator.worksheet.solar_gains import Orientation, RoofWindowInput, RooflightInput +from domain.sap10_calculator.worksheet.ventilation import MechanicalVentilationKind +from domain.sap10_calculator.worksheet.water_heating import TABLE_J1_TCOLD_FROM_MAINS_C -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( SECTION_8C_ALL_ZERO_MONTHLY, SECTION_8C_ETA_LOSS_ALL_ONE, SECTION_8C_INTERMITTENCY_MONTHLY, diff --git a/packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_001479.py b/domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/tests/_elmhurst_worksheet_001479.py rename to domain/sap10_calculator/worksheet/tests/_elmhurst_worksheet_001479.py diff --git a/packages/domain/src/domain/sap/worksheet/tests/_xlsx_loader.py b/domain/sap10_calculator/worksheet/tests/_xlsx_loader.py similarity index 93% rename from packages/domain/src/domain/sap/worksheet/tests/_xlsx_loader.py rename to domain/sap10_calculator/worksheet/tests/_xlsx_loader.py index fe836524..0c528080 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/_xlsx_loader.py +++ b/domain/sap10_calculator/worksheet/tests/_xlsx_loader.py @@ -1,6 +1,6 @@ """Reader for the canonical SAP10.2 worksheet Excel — the source of truth used to build line-by-line conformance tests against -`packages/domain/src/domain/sap/worksheet/`. +`domain/sap10_calculator/worksheet/`. The Excel file lives at the repo root and has two sheets — both contain the full worksheet, differing only on weather-data source: @@ -20,7 +20,7 @@ from typing import Any, Iterable import openpyxl -_REPO_ROOT = Path(__file__).resolve().parents[7] +_REPO_ROOT = Path(__file__).resolve().parents[4] WORKSHEET_XLSX_PATH = _REPO_ROOT / "2026-05-19-17-18 RdSap10Worksheet.xlsx" diff --git a/packages/domain/src/domain/sap/worksheet/tests/fixtures/basement/0712-3058-2202-3816-8204.json b/domain/sap10_calculator/worksheet/tests/fixtures/basement/0712-3058-2202-3816-8204.json similarity index 100% rename from packages/domain/src/domain/sap/worksheet/tests/fixtures/basement/0712-3058-2202-3816-8204.json rename to domain/sap10_calculator/worksheet/tests/fixtures/basement/0712-3058-2202-3816-8204.json diff --git a/packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0636-6824-0100-0500-6222.json b/domain/sap10_calculator/worksheet/tests/fixtures/rir/0636-6824-0100-0500-6222.json similarity index 100% rename from packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0636-6824-0100-0500-6222.json rename to domain/sap10_calculator/worksheet/tests/fixtures/rir/0636-6824-0100-0500-6222.json diff --git a/packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0636-8125-6600-0416-2202.json b/domain/sap10_calculator/worksheet/tests/fixtures/rir/0636-8125-6600-0416-2202.json similarity index 100% rename from packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0636-8125-6600-0416-2202.json rename to domain/sap10_calculator/worksheet/tests/fixtures/rir/0636-8125-6600-0416-2202.json diff --git a/packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0782-3058-6209-9186-1200.json b/domain/sap10_calculator/worksheet/tests/fixtures/rir/0782-3058-6209-9186-1200.json similarity index 100% rename from packages/domain/src/domain/sap/worksheet/tests/fixtures/rir/0782-3058-6209-9186-1200.json rename to domain/sap10_calculator/worksheet/tests/fixtures/rir/0782-3058-6209-9186-1200.json diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_dimensions.py b/domain/sap10_calculator/worksheet/tests/test_dimensions.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_dimensions.py rename to domain/sap10_calculator/worksheet/tests/test_dimensions.py index afd01852..893f7dc8 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_dimensions.py +++ b/domain/sap10_calculator/worksheet/tests/test_dimensions.py @@ -26,8 +26,8 @@ from domain.ml.tests._fixtures import ( make_floor_dimension, make_minimal_sap10_epc, ) -from domain.sap.worksheet.dimensions import Dimensions, dimensions_from_cert -from domain.sap.worksheet.tests._xlsx_loader import load_cells +from domain.sap10_calculator.worksheet.dimensions import Dimensions, dimensions_from_cert +from domain.sap10_calculator.worksheet.tests._xlsx_loader import load_cells _RIR_FIXTURES_DIR = Path(__file__).parent / "fixtures" / "rir" @@ -507,7 +507,7 @@ def test_all_rir_shapes_apply_section_1_2_45m_convention_uniformly( from types import ModuleType # noqa: E402 (kept near the Elmhurst tests) -from domain.sap.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 ALL_FIXTURES as _ELMHURST_FIXTURES, fixture_id as _elmhurst_fixture_id, ) diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py b/domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py similarity index 96% rename from packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py rename to domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py index 21e63bd9..cb1ddc81 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_e2e_elmhurst_sap_score.py +++ b/domain/sap10_calculator/worksheet/tests/test_e2e_elmhurst_sap_score.py @@ -24,9 +24,9 @@ from typing import Final import pytest -from domain.sap.calculator import Sap10Calculator -from domain.sap.rdsap.cert_to_inputs import cert_to_inputs -from domain.sap.worksheet.tests import ( +from domain.sap10_calculator.calculator import Sap10Calculator +from domain.sap10_calculator.rdsap.cert_to_inputs import cert_to_inputs +from domain.sap10_calculator.worksheet.tests import ( _elmhurst_worksheet_000474 as _w000474, _elmhurst_worksheet_000477 as _w000477, _elmhurst_worksheet_000480 as _w000480, @@ -35,7 +35,7 @@ from domain.sap.worksheet.tests import ( _elmhurst_worksheet_000516 as _w000516, _elmhurst_worksheet_001479 as _w001479, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( ALL_FIXTURES as _ELMHURST_FIXTURES, fixture_id as _elmhurst_fixture_id, ) diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_energy_requirements.py b/domain/sap10_calculator/worksheet/tests/test_energy_requirements.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_energy_requirements.py rename to domain/sap10_calculator/worksheet/tests/test_energy_requirements.py index b765adcf..0f63ec26 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_energy_requirements.py +++ b/domain/sap10_calculator/worksheet/tests/test_energy_requirements.py @@ -6,7 +6,7 @@ Reference: SAP 10.2 specification (14-03-2025) worksheet block §9a from __future__ import annotations -from domain.sap.worksheet.energy_requirements import ( +from domain.sap10_calculator.worksheet.energy_requirements import ( space_heating_fuel_monthly_kwh, ) diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_fabric_energy_efficiency.py b/domain/sap10_calculator/worksheet/tests/test_fabric_energy_efficiency.py similarity index 91% rename from packages/domain/src/domain/sap/worksheet/tests/test_fabric_energy_efficiency.py rename to domain/sap10_calculator/worksheet/tests/test_fabric_energy_efficiency.py index e1c959ed..33c0b834 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_fabric_energy_efficiency.py +++ b/domain/sap10_calculator/worksheet/tests/test_fabric_energy_efficiency.py @@ -10,10 +10,10 @@ from types import ModuleType import pytest -from domain.sap.worksheet.fabric_energy_efficiency import ( +from domain.sap10_calculator.worksheet.fabric_energy_efficiency import ( fabric_energy_efficiency_kwh_per_m2_yr, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id def test_fabric_energy_efficiency_sums_heating_per_m2_and_cooling_per_m2() -> None: diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_fuel_cost.py b/domain/sap10_calculator/worksheet/tests/test_fuel_cost.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_fuel_cost.py rename to domain/sap10_calculator/worksheet/tests/test_fuel_cost.py index 5c237a40..d2e09e99 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_fuel_cost.py +++ b/domain/sap10_calculator/worksheet/tests/test_fuel_cost.py @@ -8,8 +8,8 @@ from __future__ import annotations import pytest -from domain.sap.rdsap.cert_to_inputs import cert_to_inputs -from domain.sap.worksheet.fuel_cost import FuelCostResult, fuel_cost +from domain.sap10_calculator.rdsap.cert_to_inputs import cert_to_inputs +from domain.sap10_calculator.worksheet.fuel_cost import FuelCostResult, fuel_cost def test_single_rate_main_only_bills_kwh_at_high_rate_price() -> None: diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py b/domain/sap10_calculator/worksheet/tests/test_heat_transmission.py similarity index 99% rename from packages/domain/src/domain/sap/worksheet/tests/test_heat_transmission.py rename to domain/sap10_calculator/worksheet/tests/test_heat_transmission.py index 7a9a340d..e3f3e0ef 100644 --- a/packages/domain/src/domain/sap/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.sap.rdsap.cascade_defaults` +in `domain.ml.rdsap_uvalues` — migrates to `domain.sap10_calculator.rdsap.cascade_defaults` in Session B). Reference: SAP 10.3 specification §3 (pages 17-22); @@ -30,7 +30,7 @@ from domain.ml.tests._fixtures import ( make_floor_dimension, make_minimal_sap10_epc, ) -from domain.sap.worksheet.heat_transmission import ( +from domain.sap10_calculator.worksheet.heat_transmission import ( DwellingExposure, HeatTransmission, heat_transmission_from_cert, @@ -1132,11 +1132,11 @@ def test_real_corpus_basement_cert_has_part_with_has_basement_true() -> None: from types import ModuleType # noqa: E402 -from domain.sap.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 ALL_FIXTURES as _ELMHURST_FIXTURES, fixture_id as _elmhurst_fixture_id, ) -from domain.sap.worksheet.tests import ( # noqa: E402 +from domain.sap10_calculator.worksheet.tests import ( # noqa: E402 _elmhurst_worksheet_000474 as _w000474, _elmhurst_worksheet_000490 as _w000490, ) diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_internal_gains.py b/domain/sap10_calculator/worksheet/tests/test_internal_gains.py similarity index 99% rename from packages/domain/src/domain/sap/worksheet/tests/test_internal_gains.py rename to domain/sap10_calculator/worksheet/tests/test_internal_gains.py index eb9acd8e..3107c7a1 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_internal_gains.py +++ b/domain/sap10_calculator/worksheet/tests/test_internal_gains.py @@ -1,6 +1,6 @@ """Tests for SAP 10.2 §5 + Appendix L — internal gains. -Worksheet line refs (66)..(73) land in `domain.sap.worksheet.internal_gains` +Worksheet line refs (66)..(73) land in `domain.sap10_calculator.worksheet.internal_gains` as monthly 12-tuple outputs. Each leaf function is unit-tested against the SAP 10.2 spec formula; the orchestrator is parametrized against every Elmhurst conformance fixture in `_elmhurst_fixtures.ALL_FIXTURES`. @@ -12,7 +12,7 @@ Table 5a + Appendix L (lighting/appliances/cooking) + Appendix J Table 1b import pytest -from domain.sap.worksheet.internal_gains import ( +from domain.sap10_calculator.worksheet.internal_gains import ( InternalGainsResult, OvershadingCategory, PumpDateCategory, @@ -44,7 +44,7 @@ from datatypes.epc.domain.epc_property_data import ( SapWindow, ) from domain.ml.tests._fixtures import make_minimal_sap10_epc -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id def test_metabolic_gains_are_60w_per_occupant_constant_across_months() -> None: diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_mean_internal_temperature.py b/domain/sap10_calculator/worksheet/tests/test_mean_internal_temperature.py similarity index 97% rename from packages/domain/src/domain/sap/worksheet/tests/test_mean_internal_temperature.py rename to domain/sap10_calculator/worksheet/tests/test_mean_internal_temperature.py index 82e09e39..e1923346 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_mean_internal_temperature.py +++ b/domain/sap10_calculator/worksheet/tests/test_mean_internal_temperature.py @@ -14,14 +14,14 @@ from types import ModuleType import pytest -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.mean_internal_temperature import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.mean_internal_temperature import ( MeanInternalTemperatureResult, elsewhere_heating_temperature_c, mean_internal_temperature_monthly, off_period_temperature_reduction_c, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id # UK-average climate (region 0) external temperatures, Appendix U Table U1. diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_rating.py b/domain/sap10_calculator/worksheet/tests/test_rating.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_rating.py rename to domain/sap10_calculator/worksheet/tests/test_rating.py index 0188b688..f93f0d47 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_rating.py +++ b/domain/sap10_calculator/worksheet/tests/test_rating.py @@ -19,7 +19,7 @@ target is SAP 10.2. import pytest -from domain.sap.worksheet.rating import ( +from domain.sap10_calculator.worksheet.rating import ( energy_cost_factor, environmental_impact_rating, sap_rating, diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_section_cascade_pins.py b/domain/sap10_calculator/worksheet/tests/test_section_cascade_pins.py similarity index 99% rename from packages/domain/src/domain/sap/worksheet/tests/test_section_cascade_pins.py rename to domain/sap10_calculator/worksheet/tests/test_section_cascade_pins.py index a77b2a14..8121d7b9 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_section_cascade_pins.py +++ b/domain/sap10_calculator/worksheet/tests/test_section_cascade_pins.py @@ -16,7 +16,7 @@ from typing import Final import pytest -from domain.sap.rdsap.cert_to_inputs import ( +from domain.sap10_calculator.rdsap.cert_to_inputs import ( cert_to_inputs, energy_requirements_section_from_cert, environmental_section_from_cert, @@ -34,8 +34,8 @@ from domain.sap.rdsap.cert_to_inputs import ( ventilation_from_cert, water_heating_section_from_cert, ) -from domain.sap.worksheet.dimensions import dimensions_from_cert -from domain.sap.worksheet.tests import ( +from domain.sap10_calculator.worksheet.dimensions import dimensions_from_cert +from domain.sap10_calculator.worksheet.tests import ( _elmhurst_worksheet_000474 as _w000474, _elmhurst_worksheet_000477 as _w000477, _elmhurst_worksheet_000480 as _w000480, diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_solar_gains.py b/domain/sap10_calculator/worksheet/tests/test_solar_gains.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_solar_gains.py rename to domain/sap10_calculator/worksheet/tests/test_solar_gains.py index ad464894..3c2a19cc 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_solar_gains.py +++ b/domain/sap10_calculator/worksheet/tests/test_solar_gains.py @@ -19,8 +19,8 @@ from datatypes.epc.domain.epc_property_data import ( WindowTransmissionDetails, ) from domain.ml.tests._fixtures import make_minimal_sap10_epc, make_window -from domain.sap.worksheet.internal_gains import OvershadingCategory -from domain.sap.worksheet.solar_gains import ( +from domain.sap10_calculator.worksheet.internal_gains import OvershadingCategory +from domain.sap10_calculator.worksheet.solar_gains import ( Orientation, RoofWindowInput, RooflightInput, @@ -29,7 +29,7 @@ from domain.sap.worksheet.solar_gains import ( window_solar_gain_w, z_solar_for_overshading, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id # Worksheet U985-0001-000490 reference (UK-avg weather, region 0): diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_space_cooling.py b/domain/sap10_calculator/worksheet/tests/test_space_cooling.py similarity index 97% rename from packages/domain/src/domain/sap/worksheet/tests/test_space_cooling.py rename to domain/sap10_calculator/worksheet/tests/test_space_cooling.py index f1fbc261..4f0d8a2f 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_space_cooling.py +++ b/domain/sap10_calculator/worksheet/tests/test_space_cooling.py @@ -9,12 +9,12 @@ from types import ModuleType import pytest -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.space_cooling import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.space_cooling import ( space_cooling_monthly_kwh, utilisation_factor_loss, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id _FULLY_INACTIVE_GAINS_WINTER_TE_C: float = -10.0 diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_space_heating.py b/domain/sap10_calculator/worksheet/tests/test_space_heating.py similarity index 97% rename from packages/domain/src/domain/sap/worksheet/tests/test_space_heating.py rename to domain/sap10_calculator/worksheet/tests/test_space_heating.py index edf70840..f279cbb4 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_space_heating.py +++ b/domain/sap10_calculator/worksheet/tests/test_space_heating.py @@ -11,13 +11,13 @@ from types import ModuleType import pytest -from domain.sap.climate.appendix_u import external_temperature_c -from domain.sap.worksheet.space_heating import ( +from domain.sap10_calculator.climate.appendix_u import external_temperature_c +from domain.sap10_calculator.worksheet.space_heating import ( SpaceHeatingResult, monthly_heat_requirement_kwh, space_heating_monthly_kwh, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id _UK_AVG_EXT_TEMP_C: tuple[float, ...] = tuple( diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_utilisation_factor.py b/domain/sap10_calculator/worksheet/tests/test_utilisation_factor.py similarity index 97% rename from packages/domain/src/domain/sap/worksheet/tests/test_utilisation_factor.py rename to domain/sap10_calculator/worksheet/tests/test_utilisation_factor.py index 59731a75..d1235a72 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_utilisation_factor.py +++ b/domain/sap10_calculator/worksheet/tests/test_utilisation_factor.py @@ -9,7 +9,7 @@ Reference: SAP 10.3 specification (13-01-2026) Table 9a (page 184). import pytest -from domain.sap.worksheet.utilisation_factor import utilisation_factor +from domain.sap10_calculator.worksheet.utilisation_factor import utilisation_factor def test_small_gain_loss_ratio_returns_eta_close_to_one() -> None: diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_ventilation.py b/domain/sap10_calculator/worksheet/tests/test_ventilation.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_ventilation.py rename to domain/sap10_calculator/worksheet/tests/test_ventilation.py index 7afc1d6f..16f363a2 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_ventilation.py +++ b/domain/sap10_calculator/worksheet/tests/test_ventilation.py @@ -12,8 +12,8 @@ Canonical worked example: `2026-05-19-17-18 RdSap10Worksheet.xlsx`, import pytest -from domain.sap.worksheet.tests._xlsx_loader import load_cells -from domain.sap.worksheet.ventilation import ( +from domain.sap10_calculator.worksheet.tests._xlsx_loader import load_cells +from domain.sap10_calculator.worksheet.ventilation import ( MechanicalVentilationKind, TABLE_U2_NON_REGIONAL_WIND_SPEED_M_S, VentilationResult, @@ -461,7 +461,7 @@ def test_excel_worksheet_conformance_section_2_lines_6a_to_25m() -> None: from types import ModuleType # noqa: E402 -from domain.sap.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ( # noqa: E402 ALL_FIXTURES as _ELMHURST_FIXTURES, fixture_id as _elmhurst_fixture_id, ) @@ -479,7 +479,7 @@ def test_section_2_matches_elmhurst_worksheet(fixture: ModuleType) -> None: worksheet's (9) value. """ # Arrange - from domain.sap.worksheet.dimensions import dimensions_from_cert + from domain.sap10_calculator.worksheet.dimensions import dimensions_from_cert dims = dimensions_from_cert(fixture.build_epc()) assert dims.storey_count == fixture.LINE_9_STOREYS, ( f"dims.storey_count={dims.storey_count} should equal worksheet (9) " diff --git a/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py b/domain/sap10_calculator/worksheet/tests/test_water_heating.py similarity index 98% rename from packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py rename to domain/sap10_calculator/worksheet/tests/test_water_heating.py index fd5729aa..de31188f 100644 --- a/packages/domain/src/domain/sap/worksheet/tests/test_water_heating.py +++ b/domain/sap10_calculator/worksheet/tests/test_water_heating.py @@ -1,6 +1,6 @@ """Tests for SAP 10.2 §4 — water heating energy requirements. -Worksheet line refs land in `domain.sap.worksheet.water_heating`. Each +Worksheet line refs land in `domain.sap10_calculator.worksheet.water_heating`. Each test asserts a single line-ref output against the canonical xlsx worked example and/or Elmhurst conformance fixtures. @@ -12,14 +12,14 @@ from types import ModuleType import pytest -from domain.sap.worksheet.tests import ( +from domain.sap10_calculator.worksheet.tests import ( _elmhurst_worksheet_000474 as _w000474, _elmhurst_worksheet_000477 as _w000477, _elmhurst_worksheet_000490 as _w000490, ) -from domain.sap.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id -from domain.sap.worksheet.tests._xlsx_loader import load_cells -from domain.sap.worksheet.water_heating import ( +from domain.sap10_calculator.worksheet.tests._elmhurst_fixtures import ALL_FIXTURES, fixture_id +from domain.sap10_calculator.worksheet.tests._xlsx_loader import load_cells +from domain.sap10_calculator.worksheet.water_heating import ( TABLE_J1_TCOLD_FROM_MAINS_C, annual_average_hot_water_l_per_day, annual_average_hot_water_other_uses_l_per_day, @@ -654,7 +654,7 @@ def test_000474_cert_to_inputs_hot_water_kwh_closes_within_1pct_post_slice_2() - Equation D1 monthly cascade → effective annual η ~88% (vs the 87.0% summer scalar) → HW kWh 2320 → ~2290 (+0% target).""" # Arrange - from domain.sap.rdsap.cert_to_inputs import cert_to_inputs + from domain.sap10_calculator.rdsap.cert_to_inputs import cert_to_inputs epc = _w000474.build_epc() @@ -675,8 +675,8 @@ def test_000490_cert_to_inputs_hot_water_kwh_closes_via_equation_d1() -> None: (+6.2%). Post-slice-2 Equation D1 cascade → HW kWh closes toward 2851 (target ±2%).""" # Arrange - from domain.sap.rdsap.cert_to_inputs import cert_to_inputs - from domain.sap.worksheet.tests import _elmhurst_worksheet_000490 as _w000490 + from domain.sap10_calculator.rdsap.cert_to_inputs import cert_to_inputs + from domain.sap10_calculator.worksheet.tests import _elmhurst_worksheet_000490 as _w000490 epc = _w000490.build_epc() diff --git a/packages/domain/src/domain/sap/worksheet/utilisation_factor.py b/domain/sap10_calculator/worksheet/utilisation_factor.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/utilisation_factor.py rename to domain/sap10_calculator/worksheet/utilisation_factor.py diff --git a/packages/domain/src/domain/sap/worksheet/ventilation.py b/domain/sap10_calculator/worksheet/ventilation.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/ventilation.py rename to domain/sap10_calculator/worksheet/ventilation.py diff --git a/packages/domain/src/domain/sap/worksheet/water_heating.py b/domain/sap10_calculator/worksheet/water_heating.py similarity index 100% rename from packages/domain/src/domain/sap/worksheet/water_heating.py rename to domain/sap10_calculator/worksheet/water_heating.py diff --git a/packages/domain/src/domain/__init__.py b/packages/domain/src/domain/__init__.py deleted file mode 100644 index 1d52198c..00000000 --- a/packages/domain/src/domain/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Shared domain types for the Ara modelling pipeline and sibling Domna services. - -No persistence, no IO, no business logic. See README.md for layout. -""" diff --git a/packages/domain/src/domain/ml/demand.py b/packages/domain/src/domain/ml/demand.py index ff1840c2..8a90805a 100644 --- a/packages/domain/src/domain/ml/demand.py +++ b/packages/domain/src/domain/ml/demand.py @@ -232,7 +232,7 @@ def predicted_lighting_kwh( Missing counts treated as zero. DEPRECATED for SAP rating use. The spec-faithful Appendix L L1-L11 - cascade is in `domain.sap.worksheet.internal_gains.annual_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 diff --git a/packages/domain/src/domain/sap/worksheet/tests/__init__.py b/packages/domain/src/domain/sap/worksheet/tests/__init__.py deleted file mode 100644 index e69de29b..00000000