Price Alerts for Everything You've Purchased (#192)
Building on Friday's shorex tracking: auto-enroll no longer requires the package classifier to recognize a product. Shore excursions, spa bookings, and activity one-shots now get alert rows too, matched by exact product name throughout the checker instead of category family. If you bought it and RC drops the price, you hear about it.
One-shot purchases needed their own math: a $120 excursion is a per-event total, not a daily rate, so the below-paid comparison now has a per-event basis -- your per-person paid subtotal against the current per-person price for the same event. Cross-basis comparisons are refused outright, so a per-event total is never measured against a daily rate, and alert emails render "/person" one-time totals instead of "/day" with nights-multiplied savings.
Also in the "how was this ever working" pile: RC pads some product names with trailing whitespace, which broke exact-name matching between purchases, watches, and price history. Names are now trimmed at every boundary and matched trim-insensitively.
Queue Starvation Fix
This morning's RC scraper outage: two deadlocked month jobs got released at low priority, sat 4.5 hours behind the package backlog, and meanwhile their presence in the queue suppressed four consecutive hourly enqueues via the dedup guard. Two fixes:
- Failed-job retries now keep their original priority instead of being demoted behind everything else.
- The hourly enqueue only skips when there's a real backlog (≥25% of a batch still queued), so a few stragglers can't block a whole hour's scrape.