-- Keyset (cursor) pagination for conversation message history. -- -- An ever-growing single conversation — notably a desktop companion's ONE -- session, which now also absorbs every IM-channel turn — is loaded in -- newest-first windows via a (created_at, id) keyset cursor instead of one -- giant fetch: -- -- SELECT * FROM messages -- WHERE conversation_id = ? -- AND type NOT IN ('cron_trigger','skill_suggest') -- AND (created_at < ? OR (created_at = ? AND id < ?)) -- ORDER BY created_at DESC, id DESC -- LIMIT ? -- -- The existing idx_messages_conv_created / idx_messages_conv_created_desc cover -- (conversation_id, created_at) but NOT the `id` tiebreaker, so the cursor's -- (created_at, id) comparison and the matching ORDER BY degrade to a sort. This -- composite covers both, keeping deep "load older" pages index-only and stable -- under concurrent streaming appends. `id` is msg_{uuidv7} (time-ordered), so it -- is a sound, monotonic tiebreaker for rows sharing a created_at millisecond. CREATE INDEX IF NOT EXISTS idx_messages_conv_created_id ON messages (conversation_id, created_at DESC, id DESC);