mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-07-19 17:03:02 +00:00
The committed gate needs frozen, reproducible data without dumping real UK addresses into the repo. Add: - harness anonymise_payload + stable_hash: hash street address + cert number into opaque, dedup-stable tokens; blank secondary address lines + post_town; keep postcode + all component/lodged fields (gov data is OGL). Unit-tested. - scripts/build_epc_prediction_fixture.py: curate qualifying postcodes (>=1 SAP 10.2 target + >=2 distinct addresses) from the local scratch corpus, anonymise, freeze under tests/fixtures/epc_prediction/. - The frozen fixture: 15 postcodes / 280 certs / 36 SAP-10.2 targets. Verified no plaintext address_line_1 and post_town all blank. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
"""Behaviour of the EPC Prediction corpus anonymiser (ADR-0030): de-identify a
|
|
cert payload for the committed fixture without disturbing the component data the
|
|
scorer reads. Pure dict-in / dict-out.
|
|
"""
|
|
|
|
from harness.epc_prediction_corpus import anonymise_payload
|
|
|
|
|
|
def _payload() -> dict[str, object]:
|
|
return {
|
|
"address_line_1": "12 Acacia Avenue",
|
|
"address_line_2": "Hyde Park",
|
|
"post_town": "LEEDS",
|
|
"certificate_number": "1234-5678-9012-3456-7890",
|
|
"postcode": "LS6 1AA",
|
|
"sap_version": 10.2,
|
|
"energy_rating_current": 72,
|
|
"sap_building_parts": [{"wall_construction": 1}],
|
|
}
|
|
|
|
|
|
def test_hashes_identifiers_and_blanks_address_lines() -> None:
|
|
# Arrange
|
|
raw = _payload()
|
|
|
|
# Act
|
|
anon = anonymise_payload(raw)
|
|
|
|
# Assert — the street address + cert number are replaced by opaque tokens,
|
|
# the secondary address lines blanked.
|
|
assert anon["address_line_1"] != "12 Acacia Avenue"
|
|
assert str(anon["address_line_1"]).startswith("addr-")
|
|
assert str(anon["certificate_number"]).startswith("cert-")
|
|
assert anon["address_line_2"] == ""
|
|
assert anon["post_town"] == ""
|
|
|
|
|
|
def test_keeps_postcode_and_component_fields() -> None:
|
|
# Arrange
|
|
raw = _payload()
|
|
|
|
# Act
|
|
anon = anonymise_payload(raw)
|
|
|
|
# Assert — postcode (coarse, the cohort key) and all component / lodged data
|
|
# survive untouched.
|
|
assert anon["postcode"] == "LS6 1AA"
|
|
assert anon["sap_version"] == 10.2
|
|
assert anon["energy_rating_current"] == 72
|
|
assert anon["sap_building_parts"] == [{"wall_construction": 1}]
|
|
|
|
|
|
def test_address_hash_is_stable_for_dedup() -> None:
|
|
# Arrange — the same address re-lodged with trivial whitespace/case noise.
|
|
a = anonymise_payload({"address_line_1": "Flat 3"})
|
|
b = anonymise_payload({"address_line_1": " FLAT 3 "})
|
|
|
|
# Act / Assert — both normalise to the same token, so the dedup-by-address
|
|
# leave-one-out still collapses re-lodgements in the fixture.
|
|
assert a["address_line_1"] == b["address_line_1"]
|
|
|
|
|
|
def test_does_not_mutate_the_input() -> None:
|
|
# Arrange
|
|
raw = _payload()
|
|
|
|
# Act
|
|
anonymise_payload(raw)
|
|
|
|
# Assert — the caller's payload is left intact.
|
|
assert raw["address_line_1"] == "12 Acacia Avenue"
|