mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 21b: §1 cascade pins (TFA, Volume) — 12/12 at abs=1e-4
New file `test_section_cascade_pins.py` for per-section line-ref pins against the U985 PDF. Tests walk the actual cert→inputs cascade (not the per-section isolation tests in test_dimensions.py etc.) and assert the produced value matches the PDF line ref to abs=1e-4 for every fixture. §1 pins: (4) total_floor_area_m2 → dimensions_from_cert(epc).total_floor_area_m2 (5) volume_m3 → dimensions_from_cert(epc).volume_m3 12/12 cases pass (6 fixtures × 2 line refs). Section 1 is closed. Bottom-up plan: §1 → §2 → §3 → §4 → §5 → §6 → §7 → §8 → §9a → §10a → §11a → §12. When upstream sections close at <1e-4, downstream residuals shrink mechanically — a failing §3 pin is more legible than a sapResult.total_fuel_cost_gbp failure that could come from anywhere upstream. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
20424a2dca
commit
c147233072
1 changed files with 90 additions and 0 deletions
|
|
@ -0,0 +1,90 @@
|
|||
"""Section-by-section cascade pins against U985 PDF line refs.
|
||||
|
||||
Each pin walks the actual cert→inputs cascade (not the per-section
|
||||
isolation tests) and asserts the produced value matches the worksheet
|
||||
PDF line ref to abs=1e-4 for every fixture in the cohort. Tests run in
|
||||
worksheet order (§1, §2, §3, ..., §12) — when a pin fails the residual
|
||||
localises by section. Bottom-up discipline: a failing §3 pin gets
|
||||
fixed before §10a is touched.
|
||||
|
||||
Per `[[feedback-e2e-validation-philosophy]]`: tolerances are NOT
|
||||
widened to mask drift. A failing pin is a named calculator bug.
|
||||
|
||||
Reference: SAP 10.2 specification (14-03-2025).
|
||||
"""
|
||||
from typing import Final
|
||||
|
||||
import pytest
|
||||
|
||||
from domain.sap.rdsap.cert_to_inputs import cert_to_inputs
|
||||
from domain.sap.worksheet.dimensions import dimensions_from_cert
|
||||
from domain.sap.worksheet.tests import (
|
||||
_elmhurst_worksheet_000474 as _w000474,
|
||||
_elmhurst_worksheet_000477 as _w000477,
|
||||
_elmhurst_worksheet_000480 as _w000480,
|
||||
_elmhurst_worksheet_000487 as _w000487,
|
||||
_elmhurst_worksheet_000490 as _w000490,
|
||||
_elmhurst_worksheet_000516 as _w000516,
|
||||
)
|
||||
|
||||
|
||||
_FIXTURES: Final[dict[str, object]] = {
|
||||
"000474": _w000474,
|
||||
"000477": _w000477,
|
||||
"000480": _w000480,
|
||||
"000487": _w000487,
|
||||
"000490": _w000490,
|
||||
"000516": _w000516,
|
||||
}
|
||||
|
||||
_FLOAT_PIN_ABS: Final[float] = 1e-4
|
||||
|
||||
|
||||
def _pin(actual: float, expected: float, tag: str) -> None:
|
||||
"""Assert `actual` matches `expected` to abs=1e-4. The PDF lodges
|
||||
every worksheet line ref to 4 d.p.; anything looser is drift."""
|
||||
diff = abs(actual - expected)
|
||||
assert diff < _FLOAT_PIN_ABS, (
|
||||
f"{tag}: actual={actual}, expected={expected}, diff={diff:.6f}"
|
||||
)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# §1 Overall dwelling dimensions — LINE_4 TFA, LINE_5 Volume
|
||||
# ============================================================================
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fixture_name", list(_FIXTURES), ids=lambda x: x)
|
||||
def test_section_1_line_4_total_floor_area_matches_pdf(fixture_name: str) -> None:
|
||||
"""§1 (4) — total floor area Σ across heated storeys."""
|
||||
# Arrange
|
||||
mod = _FIXTURES[fixture_name]
|
||||
epc = mod.build_epc() # type: ignore[attr-defined]
|
||||
|
||||
# Act
|
||||
dim = dimensions_from_cert(epc)
|
||||
|
||||
# Assert
|
||||
_pin(
|
||||
dim.total_floor_area_m2,
|
||||
mod.LINE_4_TFA_M2, # type: ignore[attr-defined]
|
||||
f"§1 (4) {fixture_name}",
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("fixture_name", list(_FIXTURES), ids=lambda x: x)
|
||||
def test_section_1_line_5_volume_matches_pdf(fixture_name: str) -> None:
|
||||
"""§1 (5) — dwelling internal volume Σ across storeys."""
|
||||
# Arrange
|
||||
mod = _FIXTURES[fixture_name]
|
||||
epc = mod.build_epc() # type: ignore[attr-defined]
|
||||
|
||||
# Act
|
||||
dim = dimensions_from_cert(epc)
|
||||
|
||||
# Assert
|
||||
_pin(
|
||||
dim.volume_m3,
|
||||
mod.LINE_5_VOLUME_M3, # type: ignore[attr-defined]
|
||||
f"§1 (5) {fixture_name}",
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue