mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
implausible-lodged-score check fires for bad upstream EPC data (lodged < 13, gap >= 15) 🟩
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e70df63ee6
commit
afe1801273
2 changed files with 43 additions and 1 deletions
|
|
@ -191,7 +191,29 @@ def _effective_lodged_divergence(a: PropertyAudit) -> Optional[str]:
|
|||
|
||||
@check("implausible-lodged-score", Severity.LOW)
|
||||
def _implausible_lodged_score(a: PropertyAudit) -> Optional[str]:
|
||||
raise NotImplementedError
|
||||
"""Lodged SAP score is below 13 with a large effective-vs-lodged gap — the
|
||||
lodged figure is implausible upstream EPC register data, not a modelling bug.
|
||||
|
||||
Floor of 13 is justified against the portfolio-796 distribution: every lodged
|
||||
score below 13 either matches a known Class C exemplar (SAP 1: pids 727752,
|
||||
727008, 731205) or shares the same bad-data fingerprint — implausibly low
|
||||
lodged paired with a reasonable effective in band D/E (pids 710449 SAP 5,
|
||||
722562 SAP 7, 725377 SAP 9, 727457 SAP 10, 723364 SAP 12). SAP 13 and above
|
||||
are left in scope as ambiguous.
|
||||
|
||||
The gap guard (≥15) mirrors ``effective-lodged-divergence`` so the two checks
|
||||
partition the same population without overlap."""
|
||||
if a.lodged_sap is None or a.effective_sap is None:
|
||||
return None
|
||||
if a.lodged_sap >= 13:
|
||||
return None
|
||||
gap = a.effective_sap - a.lodged_sap
|
||||
if abs(gap) < 15:
|
||||
return None
|
||||
return (
|
||||
f"lodged SAP {a.lodged_sap:.0f} is implausible (< 13) — upstream EPC data,"
|
||||
f" not a modelling bug (effective {a.effective_sap:.0f}, Δ{gap:+.0f})"
|
||||
)
|
||||
|
||||
|
||||
@check("impossible-sap-over-100", Severity.HIGH)
|
||||
|
|
|
|||
|
|
@ -72,3 +72,23 @@ class TestImplausibleLodgedScore:
|
|||
# Assert
|
||||
assert result is not None
|
||||
assert "1" in result
|
||||
|
||||
def test_silent_when_gap_below_threshold(self) -> None:
|
||||
# Arrange — lodged=9, effective=5 (gap -4, below ±15): both low, not a divergence anomaly
|
||||
audit = _make_audit(lodged_sap=9.0, effective_sap=5.0)
|
||||
|
||||
# Act
|
||||
result = _implausible_lodged_score(audit)
|
||||
|
||||
# Assert
|
||||
assert result is None
|
||||
|
||||
def test_silent_when_lodged_sap_at_or_above_floor(self) -> None:
|
||||
# Arrange — lodged=13 is on the floor boundary; effective=70 gives large gap
|
||||
audit = _make_audit(lodged_sap=13.0, effective_sap=70.0)
|
||||
|
||||
# Act
|
||||
result = _implausible_lodged_score(audit)
|
||||
|
||||
# Assert
|
||||
assert result is None
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue