Files
WintermuteandThomas Petersen 4d74e8e0fb fix(feed): window the mentions feed per conversation to stop inbox starvation
## Problem

The Inbox collapses to a handful of rows the busier your agents get.
Reported by Morgan (3 rows spanning 12 hours) and reproduced by Thomas
(~10 rows spanning a day and a half).

## Cause

The mentions feed was a flat `ORDER BY created_at DESC LIMIT n` over
every event p-tagging the user. Clients group those events into
conversation rows *after* the cut, so the window is event-shaped while
the inbox is conversation-shaped: one chatty DM or thread (e.g. an
agent posting many consecutive callback mentions) consumes nearly every
slot, then grouping collapses them into a single row. Every
conversation older than the window is gone before the UI ever sees it.

## Fix

Window the mentions query per conversation in the relay
(`build_mentions_query`, crates/buzz-db/src/feed.rs):

- candidates: indexed `event_mentions` walk, newest-first, bounded by
  `FEED_WINDOW_SCAN_CAP` (2000)
- keyed: conversation key = `dm:<channel_id>` for DM channels, else the
  NIP-10 thread root from `thread_metadata` (event's own id for
  top-level) — mirroring the client's `getInboxConversationId`
- ranked: `ROW_NUMBER()` per conversation keeps the newest
  `FEED_CONVERSATION_EVENT_CAP` (3) events; conversations surface
  newest-activity-first, so the final `LIMIT` truncates at a
  conversation boundary

A 50-event window now spans at least ~17 distinct conversations instead
of potentially 1. No schema change.

The desktop `get_feed` mention filter now carries
`feed_types: ["mentions"]`, routing it through the relay's feed path
(which applies the windowing) instead of the flat generic query. The
kinds list is retained as the fallback bound for older relays that
ignore `feed_types`. The e2e bridge mirrors the same wire shape.

## Verification

- SQL-shape unit test (`mentions_query_windows_per_conversation`) and a
  Postgres regression (`query_mentions_survives_chatty_conversation_
  starvation`): a 40-reply chatty thread plus 6 standalone mentions in
  a 20-event window — all 7 conversations survive, chatty capped at 3.
- Before/after Playwright spec against an isolated relay seeding a
  60-message DM burst over 6 standalone mentions
  (inbox-windowing-screenshots.spec.ts): the flat window shows 1
  surviving row; the windowed path shows all 7 conversations.
- buzz-db suite, buzz-relay lib suite (879), desktop tauri tests
  (2414), desktop check/typecheck/test (4775) all green.

Co-authored-by: Thomas Petersen <thomasp@squareup.com>
Signed-off-by: Thomas Petersen <thomasp@squareup.com>
2026-08-13 23:58:35 -04:00
..