""" check_reminder_duplicate.py -- read-only: why did "John Angell Real Estate Group" get TWO 24h reminders? User report, 2026-09-28: bell showed two "in ~24h" notifications for the same lead, at 14:33 and 16:16, while the meeting is (correctly) shown as 5h35m away on the Today banner. Prints the lead's current meeting_at, every MeetingReminder row for it (the dedupe log -- see crud/meeting_reminders.py), and every stage_change event, so we can see whether meeting_at was actually edited between the two firings (the ONLY way two 24h rows can exist -- the table has a unique index on lead_id+meeting_at+stage). uv run python scripts/check_reminder_duplicate.py "John Angell" Read-only -- changes nothing. """ from __future__ import annotations import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent.parent)) from sqlalchemy import select # noqa: E402 from app.crud import leads as crud # noqa: E402 from app.database import SessionLocal # noqa: E402 from app.models import CallEvent, MeetingReminder # noqa: E402 def main() -> int: q = sys.argv[1] if len(sys.argv) > 1 else "John Angell" db = SessionLocal() try: leads = crud.list_leads(db, q=q) if not leads: print(f"No lead matching {q!r}") return 1 for lead in leads: print(f"\n#{lead.id} {lead.company_name} stage={lead.pipeline_stage} meeting_at={lead.meeting_at}" f" updated_at={lead.updated_at}") print(" MeetingReminder rows (dedupe log):") rows = db.scalars( select(MeetingReminder).where(MeetingReminder.lead_id == lead.id).order_by(MeetingReminder.created_at) ).all() for r in rows: print(f" stage={r.stage:<4} meeting_at={r.meeting_at} fired at {r.created_at}") print(" stage_change events (incl. meeting_at edits go through update_lead, not logged by value):") evs = db.scalars( select(CallEvent) .where(CallEvent.lead_id == lead.id, CallEvent.event_type == "stage_change") .order_by(CallEvent.created_at) ).all() for e in evs: print(f" {e.created_at} -> {e.outcome} (user_id={e.user_id})") finally: db.close() return 0 if __name__ == "__main__": sys.exit(main())