From 9fa4c150812f0f70d1d493c0a206d82310bf2c61 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 15 Jul 2026 08:59:14 +0000 Subject: [PATCH] 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 --- backend/jobs/check_rate_parity.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/jobs/check_rate_parity.py b/backend/jobs/check_rate_parity.py index 6b93dfb..aa23736 100644 --- a/backend/jobs/check_rate_parity.py +++ b/backend/jobs/check_rate_parity.py @@ -175,7 +175,7 @@ def gather_comparisons(db, start: date, end: date, cfg: dict) -> list: WHERE h.tier = 'own' AND r.rate_date BETWEEN :fd AND :td 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() newbook_rows = db.execute(text(""" @@ -252,8 +252,17 @@ def run_parity_check() -> dict: logger.info("Parity check skipped (disabled)") return {"status": "disabled"} - start = date.today() - end = start + timedelta(days=HORIZON_DAYS) + today = date.today() + 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)