Tig 257 stabilize explore feed ranking - #38
Conversation
…ty cap, seeded daily nudge, popularity/org-history signals, ranking docs
angelina-ji
left a comment
There was a problem hiding this comment.
Overall this looks solid and aligns well with TIG-257. I left a few comments around production-scale behavior: the fixed candidate pool, pagination consistency with the soon-event injection, and the number of per-event DB queries now that we're scoring up to 100 events.
Since we're expecting hundreds of events, I think the two correctness issues should be addressed before merge, and I'd also like to see the query pattern either batched or validated against a realistically sized dataset. Once those are updated, I can re-review and test the ranking behavior.
738e40c to
7430f6c
Compare
|
Hey, I think I addressed the issues, though I couldn't really check some things. I replaced the 100 events cap with a default dateRange filter of 14 days (so only events from the next 14 days would show up), and then put 5000 events as a safeguard in case there's too many events. For the event-ordering bug, I made it finalize the order and then paginate, so it shouldn't have the bug anymore (though I couldn't check this since there's no load more feature to move to the next page). For the benchmarking, I just counted the number of queries and latency for each method after generating 1000+ dummy events: |
| if (soonInFront < SOON_QUOTA) { | ||
| const frontIds = new Set(front.map((e) => e.id)); | ||
| const missingSoon = tail | ||
| .filter((e) => isSoon(e) && !frontIds.has(e.id)) |
There was a problem hiding this comment.
I think the soon-event injection can undo the org-diversity cap here. ranked has already deferred the 4th+ event from an org, but missingSoon pulls from tail without checking the org counts in front, so a deferred 4th event can be reinserted into the first 20 if it's imminent. That means the “max 3 per org near the top” guarantee isn't always true. Can we either preserve the cap during injection, or explicitly make/document the soon-event rule as an exception to the diversity cap?
|
Changed it so that it should only drag a soon event to the top if it's not part of an org that's already there 3 times (preserve the cap during injection) |
Summary
Stabilizes and documents Explore feed ranking (TIG-257).
Ranking formula (see
docs/ranking.mdfor full detail)score = 3.0 × interest_relevance (tag overlap with your onboarding interests)
Highest score wins. The random nudge is a deterministic hash of
(userId, today's date, eventId), so the same user sees the same order all day, but the feed varies day to day. Two extra rules run after scoring: an org can have at most 3 events near the top of the ranking (rest pushed later), and the first page always includes a few events happening within 24h even if their score is weak, so nothing imminent gets buried behind a highly-social event further out.Changes
apps/web/src/actions/events.ts: widened candidate pool (100 events, not just page size) so personalization has more impact; replaced the bucketed time score with smooth decay; added org diversity cap, tiered org affinity, popularity signal, and the seeded random nudge.docs/ranking.md: writeup of formula, each signal, and edge cases (no interests/friends/orgs).Testing
Verified against seeded data (two users with different interests get different, explainable top events; repeated calls produce identical order; a zero-signal user gets a full feed with no errors; forcing a small page size confirms the soon-event guarantee actually kicks in under truncation). Screen recordings of both seeded users' Explore pages attached below.
https://github.com/user-attachments/assets/6a8b485a-e733-4f08-ac5a-a12c1d4ac0b9
https://github.com/user-attachments/assets/b32cdb0b-0156-4141-ab4d-845445c82bde