Lorsqu’un canal ou un message privé contient plus de messages non lus que ce que charge la première page, et que quelqu’un publie un message pendant que vous parcourez cet historique, tous les messages situés entre la fin de la page chargée et le nouveau message en direct sont ignorés. La liste passe directement des anciens messages au message en direct (souvent plusieurs heures après), sans aucune indication que des messages sont manquants. Recharger le canal comble le vide une page à la fois, de sorte qu’un grand écart nécessite plusieurs rechargements.
Cela se produit indépendamment du navigateur ou du type d’appareil (testé sur Firefox Desktop et Android, ainsi que sur la PWA Chrome Android).
Étapes pour reproduire :
- L’utilisateur A et l’utilisateur B partagent un message privé ou un canal. L’utilisateur A lit jusqu’au dernier message, puis se déconnecte.
- L’utilisateur B publie plus de 60 messages.
- L’utilisateur A ouvre le message privé. Il charge autour de son dernier message lu (25 messages plus récents en dessous).
- Avant de faire défiler jusqu’en bas de cette page chargée, l’utilisateur B publie un message supplémentaire.
- L’utilisateur A fait défiler vers le bas.
Attendu : la page suivante de 25 messages se charge en dessous, et ainsi de suite jusqu’au message en direct.
Réel : le message en direct apparaît directement après la page chargée. Atteindre le bas de la liste demande des messages après le message en direct, la réponse est vide, can_load_more_future passe à false, et les plus de 35 messages intermédiaires ne sont jamais affichés. Comme le message en direct est désormais visible, last_read_message_id progresse au-delà du vide, ce qui efface également l’indicateur de messages non lus.
Voici ma meilleure tentative pour comprendre pourquoi cela se produit :
Depuis un commit vers décembre 2025 (“FEATURE: respect user presence when chat is on screen”, #36652), ChatChannel#onNewMessage route toujours le message via ChatPaneState#handleIncomingMessage, qui appelle addMessage lors du défilement automatique et via maintainScrollPosition sinon.
ChatMessagesLoader#computeNextTargetMessage utilise le dernier message non mis en attente dans la liste comme curseur pour une page FUTURE. Une fois qu’un message en direct se trouve à la fin d’une liste partiellement chargée, ce curseur saute au-delà de tout l’historique non chargé.
Ensuite, Chat::MessagesQuery.query_paginated_messages ne définit can_load_more_future que pour les pages FUTURE et can_load_more_past que pour les pages PAST. L’autre est nil. ChatMessagesLoader#loadMore assigne les deux depuis result.meta inconditionnellement, de sorte qu’une seule page PAST (en faisant défiler légèrement vers le haut après l’ouverture au dernier message lu) définit canLoadMoreFuture à null alors que l’historique en dessous est encore non chargé. La pagination supplémentaire fonctionne toujours car loadMore vérifie === false.
De plus, il existe un bug distinct et plus ancien où #sendNewMessage met le message en attente à la fin de la liste sans charger la dernière page lorsque canLoadMoreFuture est vrai. Une fois confirmé, il devient le curseur FUTURE, et le même saut se produit si vous répondez à des messages plus anciens dans l’historique que vous lisez.
Notre communauté n’est pas principalement axée sur la discussion en temps réel, mais nos utilisateurs relisent fréquemment, ce qui fait que des messages manquants dans une conversation en cours à laquelle vous n’avez pas participé constituent un problème. J’imagine que ce sera un problème encore plus important pour les communautés dont l’activité principale est la discussion en temps réel, surtout compte tenu de la nouvelle possibilité de définir la page d’accueil comme le chat.