تتخطى الدردشة كتلة من الرسائل عندما ينشر أحدهم أثناء تصفحك لسجل الرسائل غير المقروءة

عند وجود قناة أو رسالة خاصة (DM) تحتوي على رسائل غير مقروءة أكثر مما يُحمَّله الصفحة الأولى، وإذا قام شخص ما بالنشر أثناء تمريرك عبر السجل، يتم تخطي كل الرسائل الموجودة بين نهاية الصفحة المحملة والرسالة الحية الجديدة. ينتقل القوائم مباشرة من الرسائل القديمة إلى الرسالة الحية (والتي غالباً ما تكون متأخرة بساعات)، ولا يوجد أي مؤشر يدل على فقدان أي شيء. يعيد تحميل القناة ملء الفراغ صفحة واحدة في كل مرة، لذا يستغرق الفراغ الكبير عدة عمليات إعادة تحميل.

يحدث هذا بغض النظر عن نوع المتصفح أو الجهاز (تم الاختبار على متصفح Firefox لنظام Desktop وAndroid وPWA لمتصفح Chrome على Android).

خطوات إعادة الإنتاج:

  1. يتشارك المستخدم A والمستخدم B في رسالة خاصة (DM) أو قناة. يقرأ المستخدم A حتى أحدث رسالة، ثم يغادر.
  2. ينشر المستخدم B أكثر من 60 رسالة.
  3. يفتح المستخدم A الرسالة الخاصة (DM). يتم تحميل الرسائل حول آخر رسالة قرأها (حوالي 25 رسالة جديدة أدناه).
  4. قبل التمرير إلى أسفل الصفحة المحملة، ينشر المستخدم B رسالة إضافية.
  5. يقوم المستخدم A بالتمرير للأسفل.

المتوقع: يتم تحميل الصفحة التالية المكونة من 25 رسالة أدناه، وهكذا حتى الوصول إلى الرسالة الحية.

الفعلي: تظهر الرسالة الحية مباشرة بعد الصفحة المحملة. عند الوصول إلى الأسفل، يتم طلب الرسائل التي تلي الرسالة الحية، تكون الاستجابة فارغة، تصبح can_load_more_future بقيمة false، ولا يتم عرض الـ 35+ رسالة الموجودة في المنتصف أبداً. وبما أن الرسالة الحية أصبحت مرئية الآن، يتقدم last_read_message_id متجاوزاً الفراغ، وبالتالي يختفي مؤشر الرسائل غير المقروءة أيضاً.

فيما يلي أفضل محاولة مني لفهم سبب حدوث هذا:

منذ الالتزام (commit) حوالي ديسمبر 2025 (“FEATURE: respect user presence when chat is on screen”, #36652)، يقوم ChatChannel#onNewMessage دائماً بتوجيه الرسالة عبر ChatPaneState#handleIncomingMessage، والذي يستدعي addMessage عند التمرير التلقائي وعبر maintainScrollPosition بخلاف ذلك.

يستخدم ChatMessagesLoader#computeNextTargetMessage آخر رسالة غير مرحلية (non-staged) في القائمة كمؤشر (cursor) للصفحة المستقبلية (FUTURE page). بمجرد أن تجلس رسالة حية في نهاية قائمة محملة جزئياً، يقفز هذا المؤشر متجاوزاً كل السجل غير المحمل.

ثم، يقوم Chat::MessagesQuery.query_paginated_messages بتعيين can_load_more_future للصفحات المستقبلية (FUTURE pages) فقط، وcan_load_more_past للصفحات السابقة (PAST pages) فقط. تكون القيمة الأخرى nil. يخصص ChatMessagesLoader#loadMore كلاهما من result.meta دون قيد، لذا فإن صفحة سابقة واحدة (التمرير لأعلى قليلاً بعد الفتح عند آخر رسالة مقروءة) تعيين canLoadMoreFuture إلى null بينما السجل أدناه لا يزال غير محمل. يستمر العمل الإضافي (pagination) في العمل لأن loadMore يفحص === false.

بالإضافة إلى ذلك، هناك خطأ منفصل وأقدم حيث يقوم #sendNewMessage بترحيل (stages) الرسالة في نهاية القائمة دون تحميل أحدث صفحة عندما تكون canLoadMoreFuture بقيمة true. بمجرد تأكيدها، تصبح مؤشر الفUTURE، لذا يحدث نفس التخطي إذا قمت بالرد على رسائل أقدم في السجل الذي تقرأه.

مجتمعنا ليس مركزياً في المقام الأول على الدردشة، لكن مستخدمينا يقومون بالقراءة الراجعة (back read) بشكل متكرر، لذا فإن فقدان الرسائل في محادثة جارية لم تكن حاضراً فيها يمثل مشكلة. أتخيل أنها ستكون مشكلة أكبر للمجتمعات التي تعتمد بشكل أساسي على الدردشة، خاصة بالنظر إلى القدرة الجديدة على تعيين الصفحة الرئيسية لتكون الدردشة.