mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Locality of reference — SAP-specific docs, specs, and runtime data
now live alongside the calculator that consumes them, mirroring the
prior packages→domain layout moves.
Move targets:
- Narrative MDs → domain/sap10_calculator/docs/
NEXT_AGENT_PROMPT.md, HANDOVER_NEXT.md, SAP_CALCULATOR.md
- Spec PDFs → domain/sap10_calculator/docs/specs/
RdSAP 10 Specification 10-06-2025.pdf
PCDF_Spec_Rev-06b_12_May_2021.pdf
sap-10-2-full-specification-2025-03-14.pdf
sap-10-3-full-specification-2026-01-13.pdf
- PCDB runtime data → domain/sap10_calculator/tables/pcdb/data/
pcdb10.dat (8.3MB) + 7× pcdb_table_*.jsonl (18MB total)
Path code rewrites (load-bearing):
- tables/pcdb/__init__.py: replaced parents[4]/'docs'/'sap-spec' with
Path(__file__).resolve().parent/'data' for Table 105 JSONL loading.
- tables/pcdb/postcode_weather.py: same rebase for the pcdb10.dat path
read by _postcode_climate_table().
- tables/pcdb/etl.py __main__: same rebase for the manual ETL invocation
(source + output_dir both now point inside the package).
- tests/test_pcdb_etl.py: _PCDB_DAT_PATH now derives from
parents[1]/'tables'/'pcdb'/'data' (was parents[3]/'docs'/'sap-spec').
Citation rewrites:
- 12 .py docstrings and 4 .md docs (ADRs + READMEs + narrative docs)
had `docs/sap-spec/<file>` strings rewritten to their new locations.
- Two cases where the catch-all sed misfired (an ADR-0009 line about a
PCDB extract; the pcdb __init__.py docstring about ETL output) were
hand-corrected to point at tables/pcdb/data/ rather than docs/specs/.
docs/sap-spec/ is now empty (will be removed in a follow-up sweep or
left as a vestigial empty dir for future repurposing). ADRs 0009 and
0010 remain at docs/adr/ — they're part of the chronological
cross-cutting decision log, not calculator-specific narrative.
Verified:
- Calculator's 1e-4 production gate
(test_api_001479_full_chain_sap_matches_worksheet_pdf_exactly) GREEN.
- Wider sweep (domain/sap10_calculator/ + domain/sap10_ml/): 1654
passed / 20 failed — exact pre-move baseline. All 20 failures
pre-existing (10 hand-built skeleton + 4 cohort chain + 6 cohort
diff).
- Pyright net-zero on the 4 touched runtime/test files (0 errors)
and unchanged on heat_transmission.py (13) / cert_to_inputs.py (35) /
mapper.py (33).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
82 lines
2.9 KiB
Python
82 lines
2.9 KiB
Python
"""SAP 10.2 (14-03-2025 amendment) Table 12 value-correctness tests.
|
|
|
|
Locks the CO2 emission factors and primary energy factors against the
|
|
published SAP 10.2 specification at
|
|
`domain/sap10_calculator/docs/specs/sap-10-2-full-specification-2025-03-14.pdf`, page 189.
|
|
|
|
The price column (`UNIT_PRICE_P_PER_KWH`) was already SAP 10.2-correct
|
|
when the calculator code was authored; the CO2 column was authored
|
|
against SAP 10.3 (13-01-2026) values by mistake. ADR-0010 retargets the
|
|
calculator to SAP 10.2 (14-03-2025) until the corpus migrates, so the
|
|
CO2 column was corrected during P2.4. These tests lock the corrected
|
|
values.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import pytest
|
|
|
|
from domain.sap10_calculator.tables.table_12 import (
|
|
co2_factor_kg_per_kwh,
|
|
primary_energy_factor,
|
|
unit_price_p_per_kwh,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"fuel_code, expected_co2_kg_per_kwh, fuel_name",
|
|
[
|
|
# Most-common cases first — gas + electricity dominate the corpus.
|
|
(1, 0.210, "mains gas"),
|
|
(30, 0.136, "standard tariff electricity"),
|
|
# Sanity: heating oil is unchanged between SAP 10.2 and SAP 10.3.
|
|
(4, 0.298, "heating oil"),
|
|
# Off-peak electricity tariffs all share the annual-average factor.
|
|
(31, 0.136, "7-hour low rate electricity"),
|
|
(35, 0.136, "24-hour heating tariff"),
|
|
# Bulk LPG — SAP 10.2 says 0.241 (file had 0.24 rounded).
|
|
(2, 0.241, "bulk LPG"),
|
|
],
|
|
)
|
|
def test_co2_factor_matches_sap_10_2_table_12(
|
|
fuel_code: int, expected_co2_kg_per_kwh: float, fuel_name: str
|
|
) -> None:
|
|
# Arrange — table_12.co2_factor_kg_per_kwh is the only CO2 source
|
|
# in the calculator pipeline (see cert_to_inputs._co2_factor_kg_per_kwh).
|
|
# Act
|
|
actual = co2_factor_kg_per_kwh(fuel_code)
|
|
|
|
# Assert
|
|
assert actual == pytest.approx(expected_co2_kg_per_kwh, abs=1e-6), (
|
|
f"{fuel_name} (code {fuel_code}): expected SAP 10.2 CO2 factor "
|
|
f"{expected_co2_kg_per_kwh}, got {actual}. See SAP 10.2 PDF p.189."
|
|
)
|
|
|
|
|
|
def test_default_co2_factor_is_mains_gas_baseline() -> None:
|
|
# Arrange — unknown fuel codes fall back to mains gas (the SAP 10.2
|
|
# convention; see table_12._DEFAULT_CO2_KG_PER_KWH).
|
|
# Act
|
|
actual = co2_factor_kg_per_kwh(None)
|
|
|
|
# Assert
|
|
assert actual == pytest.approx(0.210, abs=1e-6)
|
|
|
|
|
|
def test_mains_gas_unit_price_unchanged_at_sap_10_2_value() -> None:
|
|
# Arrange — sanity: prices were already SAP 10.2-correct before P2.4.
|
|
# This locks that we didn't accidentally regress them while fixing CO2.
|
|
# Act
|
|
actual = unit_price_p_per_kwh(1)
|
|
|
|
# Assert
|
|
assert actual == pytest.approx(3.64, abs=1e-6)
|
|
|
|
|
|
def test_standard_electricity_primary_energy_factor_unchanged() -> None:
|
|
# Arrange — sanity: PE factor for electricity is 1.501 in both SAP
|
|
# 10.2 and SAP 10.3; locks that P2.4 didn't touch the PEF column.
|
|
# Act
|
|
actual = primary_energy_factor(30)
|
|
|
|
# Assert
|
|
assert actual == pytest.approx(1.501, abs=1e-6)
|