mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
run_property_report builds the three-section Markdown+CSV report over a dir of API-shaped EPC JSON, offline (defaults to the golden 57: 57/57 scorable, MAE 0.54, 6 flagged |Δ|>0.5). fetch_epc_dump pulls raw cert JSON from the live API by --uprn/--postcode (picking the latest cert per match, skipping existing files), mirroring fetch_cohort2's proven HTTP shape and reading OPEN_EPC_API_TOKEN. Report artifacts + epc_dump/ are gitignored. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
2.5 KiB
Python
70 lines
2.5 KiB
Python
"""Build the per-property inspection report over an EPC-JSON dump, offline.
|
|
|
|
Reads a directory of API-shaped EPC JSON (identical to the EPC API response —
|
|
what `from_api_response` parses), runs each cert through the Modelling harness,
|
|
and writes the three-section report (calculator error vs lodged SAP, Plans +
|
|
costings, recommended measures + their triggers) as Markdown and CSV. No
|
|
database, no network — run it against a cached dump fetched by
|
|
`scripts.fetch_epc_dump`. Run from the worktree root so imports resolve to this
|
|
checkout, not /workspaces/model.
|
|
|
|
# no args -> the committed golden cohort (57 real API certs)
|
|
python -m scripts.run_property_report
|
|
|
|
# your fetched dump, optional goal band (default C)
|
|
python -m scripts.run_property_report epc_dump C
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
_REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(_REPO_ROOT)) # worktree root first — avoid the import trap
|
|
|
|
from harness.report import ( # noqa: E402
|
|
build_property_reports,
|
|
format_report_csv,
|
|
format_report_markdown,
|
|
parity_report_for,
|
|
)
|
|
|
|
_DEFAULT_DIR = _REPO_ROOT / "tests/domain/sap10_calculator/rdsap/fixtures/golden"
|
|
_MARKDOWN_PATH = Path("property_report.md")
|
|
_CSV_PATH = Path("property_report.csv")
|
|
|
|
|
|
def main() -> None:
|
|
args = sys.argv[1:]
|
|
directory = Path(args[0]) if args else _DEFAULT_DIR
|
|
goal_band = args[1] if len(args) > 1 else "C"
|
|
paths = sorted(directory.glob("*.json"))
|
|
if not paths:
|
|
print(f"no *.json files under {directory}")
|
|
raise SystemExit(1)
|
|
|
|
print(
|
|
f"building inspection report over {len(paths)} EPC JSON(s) from "
|
|
f"{directory} (goal band {goal_band}), offline — no database...\n"
|
|
)
|
|
reports = build_property_reports(paths, goal_band=goal_band)
|
|
|
|
parity = parity_report_for(reports)
|
|
flagged = sum(1 for report in reports if report.sap_error_exceeds_threshold)
|
|
errored = sum(1 for report in reports if report.calculator_error is not None)
|
|
print(
|
|
f"calculator parity: {parity.case_count} scorable · "
|
|
f"MAE {parity.global_mae:.2f} · bias {parity.global_bias:+.2f}\n"
|
|
f"flagged |Δ|>0.5 : {flagged}\n"
|
|
f"calculator errors: {errored}"
|
|
)
|
|
|
|
_MARKDOWN_PATH.write_text(format_report_markdown(reports), encoding="utf-8")
|
|
_CSV_PATH.write_text(format_report_csv(reports) + "\n", encoding="utf-8")
|
|
print(f"\nwrote {_MARKDOWN_PATH.resolve()}")
|
|
print(f"wrote {_CSV_PATH.resolve()}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|