Fix parity check: always compare lead-in rate + auto-resolve past alerts

- DISTINCT ON tiebreaker was undefined when scraper writes multiple room
  types in one batch (same scraped_at); adding rate_gross ASC ensures we
  always pick the cheapest (lead-in / best available) rate, matching like
  for like against the Newbook BAR tariff
- Past-date active alerts were never touched (start = today meant they
  fell outside the query window); now resolved at the top of each run

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-15 08:59:14 +00:00
parent 4b5b8b30ed
commit 9fa4c15081

View file

@ -175,7 +175,7 @@ def gather_comparisons(db, start: date, end: date, cfg: dict) -> list:
WHERE h.tier = 'own' WHERE h.tier = 'own'
AND r.rate_date BETWEEN :fd AND :td AND r.rate_date BETWEEN :fd AND :td
AND r.rate_gross IS NOT NULL AND r.rate_gross IS NOT NULL
ORDER BY r.rate_date, r.scraped_at DESC ORDER BY r.rate_date, r.scraped_at DESC, r.rate_gross ASC
"""), {"fd": start, "td": end}).mappings().all() """), {"fd": start, "td": end}).mappings().all()
newbook_rows = db.execute(text(""" newbook_rows = db.execute(text("""
@ -252,8 +252,17 @@ def run_parity_check() -> dict:
logger.info("Parity check skipped (disabled)") logger.info("Parity check skipped (disabled)")
return {"status": "disabled"} return {"status": "disabled"}
start = date.today() today = date.today()
end = start + timedelta(days=HORIZON_DAYS) start = today
end = today + timedelta(days=HORIZON_DAYS)
# Resolve any lingering active alerts for dates that have already passed
db.execute(text("""
UPDATE rate_parity_alerts
SET alert_status = 'resolved'
WHERE alert_status = 'active'
AND rate_date < :today
"""), {"today": today})
comparisons = gather_comparisons(db, start, end, cfg) comparisons = gather_comparisons(db, start, end, cfg)