mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-12 13:29:04 +00:00
A focused sibling to audit-ara-portfolio: that skill audits baselines/plans/SAP; this one audits the *recommendations themselves* — why a measure was or wasn't offered. Motivated by the portfolio-814 review (Khalim's HHRSH-on-community- heating, missing-HHRSH, missing-secondary-heating-removal, and a neighbour split). Adds: - .claude/skills/find-weird-recommendations/SKILL.md — scan -> neighbour scan -> live re-model deep-dive -> root-cause -> codify, with a seeded known-bug catalogue and the query-safety rules inherited from audit-ara-portfolio. - scripts/audit/anomalies.py: new `plan-stops-short-of-goal` HIGH check — the default plan ends below the goal band on an unlimited-budget scenario (the deterministic worklist for "why didn't this get recommended X"). Adds scenario_budget to the bundle/query so budget-capped scenarios are excluded. - scripts/audit/neighbour_divergence.py: groups a portfolio by (postcode, property_type, built_form) and flags effective-SAP outliers vs the cohort median. Never touches the 26m-row recommendation table, so it is safe portfolio-wide. - Tests for both (12 passing). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
76 lines
2.2 KiB
Python
76 lines
2.2 KiB
Python
from typing import Optional
|
|
|
|
from scripts.audit.neighbour_divergence import Neighbour, find_divergences
|
|
|
|
|
|
def _n(
|
|
property_id: int,
|
|
*,
|
|
effective_sap: Optional[float],
|
|
postcode: str = "AB1 2CD",
|
|
property_type: str = "Flat",
|
|
built_form: str = "Mid-Terrace",
|
|
floor_area_m2: float = 60.0,
|
|
) -> Neighbour:
|
|
return Neighbour(
|
|
property_id=property_id,
|
|
uprn=None,
|
|
postcode=postcode,
|
|
property_type=property_type,
|
|
built_form=built_form,
|
|
floor_area_m2=floor_area_m2,
|
|
effective_sap=effective_sap,
|
|
effective_band=None,
|
|
)
|
|
|
|
|
|
class TestFindDivergences:
|
|
def test_flags_the_outlier_neighbour(self) -> None:
|
|
# Arrange — three identical-cohort flats, one sits a clear band below.
|
|
cohort = [
|
|
_n(1, effective_sap=70.0),
|
|
_n(2, effective_sap=72.0),
|
|
_n(3, effective_sap=50.0), # Δ-20 vs median 70
|
|
]
|
|
|
|
# Act
|
|
result = find_divergences(cohort, min_gap=12.0)
|
|
|
|
# Assert — only the outlier is flagged.
|
|
assert [d.property_id for d in result] == [3]
|
|
|
|
def test_silent_when_cohort_agrees(self) -> None:
|
|
# Arrange — neighbours within a few SAP points of each other.
|
|
cohort = [_n(1, effective_sap=70.0), _n(2, effective_sap=68.0)]
|
|
|
|
# Act
|
|
result = find_divergences(cohort, min_gap=12.0)
|
|
|
|
# Assert
|
|
assert result == []
|
|
|
|
def test_singletons_never_flagged(self) -> None:
|
|
# Arrange — one flat here, one house there: neither has a peer to diverge from.
|
|
lonely = [
|
|
_n(1, effective_sap=30.0, property_type="Flat"),
|
|
_n(2, effective_sap=90.0, property_type="House"),
|
|
]
|
|
|
|
# Act
|
|
result = find_divergences(lonely, min_gap=12.0)
|
|
|
|
# Assert
|
|
assert result == []
|
|
|
|
def test_different_postcode_is_a_different_cohort(self) -> None:
|
|
# Arrange — same type/form but different postcodes: not neighbours.
|
|
split = [
|
|
_n(1, effective_sap=40.0, postcode="AB1 2CD"),
|
|
_n(2, effective_sap=80.0, postcode="ZZ9 9ZZ"),
|
|
]
|
|
|
|
# Act
|
|
result = find_divergences(split, min_gap=12.0)
|
|
|
|
# Assert
|
|
assert result == []
|