Casino Offer Deadlines
We'd been treating the "Expires {date}" timestamp on a Club Royale offer as a precise UTC moment, which had been silently flagging offers as Expired ~22 hours before they actually were. An offer displaying "Expires May 6" was being marked Expired throughout May 6 itself.
Per Club Royale agents (verified today): the displayed date is the last bookable day, usable until 10 PM ET on that date -- or 5:30 PM ET on Saturday and Sunday. RC stamps the field with a near-midnight UTC timestamp that lands on the prior calendar day in ET, which is what was tripping every previous version of this logic.
This was fixed in four places that had all developed their own copy of the old expiration check:
- Homepage CASINO OFFERS picker -- both its SQL filter (
reserve_by_date >= CURRENT_DATEin UTC-mode Postgres) and its PHPdaysLeftcalc were dropping offers ~22h early. /casinopage -- the canonical surface, fixed first.- Sailing detail page -- four separate inlined copies of the old logic, all replaced with the canonical helper.
- Offer-detail page -- the "Book by" label used to subtract a day from the displayed date.
Now there's a single helper (CasinoOffer::ComputeEffectiveDeadline) and every surface calls it. The homepage filter, the /casino table, the sailing detail page, the offer-detail "Book by" label, and email all agree on what counts as active.
Personalized Price Drop Alerts: Anomaly Defense Layer 2
The other thing that happened today: my own account got 21 "personalized drop" alerts across 6 sailings, all bogus.
When RC's API briefly serves a downgrade promo (e.g. their 20% pre-cruise rate instead of my 50% Club Royale Prime rate) for one personalized snapshot, the prior defense (added Apr 30) correctly suppressed the fake drop. But this morning RC served the same downgrade for two consecutive snapshots, which satisfied the old "match the previous snapshot" check, and 13 fake drop alerts fired against the inflated baseline -- DBP $54.99 → $87.99, UDP $26 → $42.
New defense layer: a snapshot now also has to stay within $5/day of the dominant (mode) personalized price across the prior 5 snapshots before it's treated as a valid baseline. Anomaly clusters up to 4 snapshots long can't become the mode. Real drops still fire when a price actually moves; spurious downgrade clusters get suppressed.
While I was in there, also fixed an email subject bug: it now counts distinct bookings, not distinct ship names. So two Navigator + two Rhapsody sailings no longer collapse to "6 sailings" when 8 are actually listed in the body.