Purchased VOOM Disappeared (user report)
Royal Caribbean quietly rebranded "VOOM Surf & Stream" to "VOOM High Speed Internet Package - N Devices". Our internet classifier only knew the old name, so anyone who bought the new SKU saw their purchase drop out of the dashboard's internet column, and personalized VOOM rows stopped matching internet alerts. A user wrote in about a 2-device VOOM that wasn't showing up, which is how we found it.
The wrinkle: RC serves both naming generations at the same time (in the last 30 days, 36K old-name rows vs 17K new-name rows in the public feed). So this wasn't a rename to chase; every place that matches a package by name now goes through one classifier that accepts both. The sailing page summary, the default chart lines, Market Pulse's internet trend (which had been silently averaging only old-name rows), and the canonical alert product were all switched over.
Below-Paid Alerts Could Only Fire Once, Ever
The "current price is under what you paid" alert was gated on a column that gets set permanently the first time any alert fires for that watch, including an ordinary snapshot-over-snapshot drop. So one notification of any kind killed the below-paid path for good. 34 active purchase-linked watches in production were already dead-ended.
It now tracks the price it last told you about and re-fires only when the price beats that mark. A permanently-cheaper package alerts once per new low instead of once ever, and never every six hours. A per-event total is never compared against a per-day rate; that counts as no baseline.
Carnival's Maintenance Page Poisoned the Cache
Carnival served its site-wide maintenance page on HTTP 200 for a stretch on 8/29. Two latent weaknesses turned that into a hard-to-diagnose failure: the scraper wrote the response to the hourly cache before checking it parsed, so the retry short-circuited on the poisoned file without re-requesting; and a body that failed to parse logged nothing at all. Now only parsed responses are cached, a non-JSON 200 logs its status, size, and first bytes, and an unparseable cache file is treated as a miss so a bad hour heals itself.
Related, from the same sweep: six scrapers (Carnival, HAL, MSC, Princess, Silversea, Virgin) had never persisted an HTTP code to their run records because two similarly-named methods did different things. Regent was fabricating a single 200 per run even when served from cache. Every code is now tallied and flushed to the run on every exit path, failures included. Scraper runs orphaned by a deploy are also reaped every 15 minutes instead of only at the next worker restart; production had five rows stuck "running" for nearly 30 hours.
Same Login, Several Accounts
When the same cruise-line login is linked under multiple site users, scheduled sync now runs once for the group and mirrors the results (profile, loyalty, offers, bookings, purchases) to the siblings, instead of logging in N times. Linking a login that another user already has is now refused up front.
A Packages-Only Worker
Package price throughput turned out to be limited by worker attention, not the rate limiter (about 4.8K jobs a day processed against 34K allowed), so the 14K daily backlog never drained. Worker 2 now watches only the package tube, mirroring the price lane added last week. Six workers total.
Health alert emails also got a rewrite while I was in there: every check now reports pass, fail, or unknown, and both alert and all-clear emails show the full board with failures on top, so a "resolved" notice can't read as all-clear while something else is still red.