eleven / ocho Public

server: stable chat-list order for same-second activity (#73)

The thread sort tiebroke on second-resolution timestamps, so two threads
with activity in the same second ordered arbitrarily — visible as list
jitter and as the TestThreadPinned flake. Message ids are monotonic, so
they break the tie deterministically.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell 6d15db16678b020cf93690e33eb2330d9d0cbb58 parent 1b0f041
1 file changed, +3 −0
  • db.go +3 −0
diff --git a/db.go b/db.go
index aa337d7..d8530d7 100644
--- a/db.go
+++ b/db.go
@@ -1165,6 +1165,9 @@ func (db *DB) threadsForUser(userID string) ([]Thread, error) {
WHERE m.user_id = ?
ORDER BY pinned DESC,
COALESCE((SELECT MAX(created_at) FROM messages WHERE thread_id = t.id), t.created_at) DESC,
+ -- created_at is second-resolution, so threads active in the same
+ -- second tie; message ids are monotonic, making the order stable.
+ COALESCE((SELECT MAX(id) FROM messages WHERE thread_id = t.id), 0) DESC,
t.created_at DESC`, userID)
if err != nil {
return nil, err