Skip to content

Commit bebd30d

Browse files
committed
timeline: globally-loved lane — broad consensus bypasses the follow gate
The logged-in feed was strictly follow-graph-gated: a resource co-signed by dozens of VIPs you happen not to follow would never reach you. Found live — a 28-VIP launch was #1 in the anon feed but invisible to a viewer who didn't follow those sharers. Add a disjunct to the logged-in WHERE: a row also passes when vip_sharer_count >= 10 (broad consensus), not only when its sharers intersect your followees. The threshold is high — only 86 of ~59k anchors clear it — so this adds the standout consensus items, not a flood of non-followed content. The hide-already-seen / hide-already- owned filters still apply, so it stays discovery (not a re-run of your library). Keeps the score-index walk: the disjunct is a cheap per-row check and broad-consensus rows already rank high, so they're hit early. Logged-in path only (uncached); anon path unchanged.
1 parent 9dfd2f7 commit bebd30d

1 file changed

Lines changed: 19 additions & 4 deletions

File tree

api/src/handlers/follows.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,7 +577,19 @@ pub async fn timeline(
577577
), 0) >= $11::int) AS already_seen
578578
FROM feed_snapshot s
579579
WHERE
580-
-- Logged-in: sharer_user_ids must intersect followees.
580+
-- Logged-in: sharer_user_ids must intersect followees,
581+
-- OR the resource is globally-loved — co-signed by at
582+
-- least 10 distinct VIPs. Without
583+
-- the second clause the personalised feed is strictly
584+
-- follow-graph-gated, so a resource validated by dozens
585+
-- of VIPs you happen not to follow would NEVER reach you
586+
-- (the gap we found: a 28-VIP launch invisible to a
587+
-- viewer who follows none of those 28). The threshold is
588+
-- high (≥10 VIPs is rare — most anchors have 1-3) so this
589+
-- adds only the standout consensus items, not a flood of
590+
-- non-followed content. The already-seen / already-owned
591+
-- filters below still apply, so it's discovery, not a
592+
-- re-run of your own library.
581593
-- Anon: rely on any_vip_sharer (partial-indexed scan).
582594
--
583595
-- We deliberately *don't* use `&&` directly here — its
@@ -586,10 +598,13 @@ pub async fn timeline(
586598
-- which costs 600 ms+ before the LIMIT even runs.
587599
-- Wrapping in `INTERSECT` is opaque to the GIN operator
588600
-- class so the planner picks `idx_feed_snapshot_score`
589-
-- and walks it score-DESC, stopping at LIMIT × 2.
590-
-- For an active viewer this scans ~200 rows instead of
591-
-- 50 000 → from 3.4 s down to ~10 ms.
601+
-- and walks it score-DESC, stopping at LIMIT × 2. The
602+
-- added `vip_sharer_count >= 10` disjunct keeps that walk
603+
-- (it's a cheap per-row check on the score-ordered scan),
604+
-- it just admits the broad-consensus rows early — and
605+
-- those already sit high by score, so they're hit fast.
592606
($1 IS NULL
607+
OR s.vip_sharer_count >= 10
593608
OR cardinality(ARRAY(
594609
SELECT unnest(s.sharer_user_ids)
595610
INTERSECT

0 commit comments

Comments
 (0)