What both change
The inbox used to download every conversation and sort it on the client into Priority, General, and Message Lists. Rows with an empty last_message were dropped. Both pull requests stop that. A creator asks for one tab, featured, general, or broadcast, always with counts=true. A fan sends tab=all. The next page adds the cursor from the last reply. A new search or a tab change starts again with no cursor.
History used to page with timeStamp, and scroll-up was commented out. Both send { groupId, include_validation: true } on the first page of a direct message and { groupId, cursor } after that. ChatUserValidation is deleted. Older messages are prepended.
| 10895 | 10896 | |
|---|---|---|
| Head | 802f734e5a4c | af7fcdb53bc3 |
| Diff | 3 files, 426 additions, 169 deletions | 8 files, 559 additions, 282 deletions |
| Live check | Jon Snow on staging. First pages, search, and a DM history POST. | Empty creator inbox live. The rest is controlled responses. |
Why 10895
Merge this one.
The earlier Jon Snow pass, at localhost:4202/messages, is written up in the verification note. Priority, General, and Message Lists each requested their own first page. Search sent search_key=Noel on featured and search_key=Prateek on general, and clearing the box dropped the key. Noel Huber's history POST was groupId plus include_validation: true. No chat-user-validation. Every cursor on that account was null, so the append page never left the browser. Scrolling the 30-row General list sent no second GET. That scroll used infiniteScroll inside ng-scrollbar, the same directive the thread pane already uses.
Next pages append and skip a groupId already on the list. History prepends and moves .ng-scroll-viewport by the height that was added, so you stay on the same bubble. Broadcast and followers do not send include_validation. Broadcast still sends from.
Opening a thread does not refetch the inbox. If you scrolled down the left list, that row stays put. Unread still zeros on the row, and the stored counts drop by that row's unread so the Priority and General pills do not bounce back until the next inbox GET. Message Lists still has no pill. The sidebar total is general + featured + broadcast.
The change stays in the messages component, its template, and messages.constant.ts. buildChatInboxUrl runs the query through URLSearchParams, so a cursor with + or / survives.
Why 10896 stays closed
Close it.
After the first history page lands, getUserChatMessage calls getUserChatLogs. That method clears the open tab and requests page 1. Every thread you open throws away the inbox page you scrolled to. The badge refresh is real. The list jump is the cost, and it happens on the screen you are looking at.
The inbox next page is a scroll listener on the inner scrollViewport div, firing inside 100 pixels of the bottom. ng-scrollbar 9 does use that content child as the viewport, so the listener is on the element that scrolls. It still only runs when the user actually scrolls. A first page shorter than the pane never overflows, so a leftover cursor is never requested. infiniteScroll is what this screen already uses for that case. The PR's passing scroll check handed onInboxScroll a viewport object. It did not show a thumb drag inside the scrollbar.
The first history POST always sets include_validation, including a message list. Jon Snow's contract for a message list is from, and no validation flag. 10896 attaches from for broadcast, then asks for validation anyway, and treats a missing validation object as fine for that lock.
Appended inbox rows and prepended messages are not deduped. The same cursor twice paints the same rows twice.
docs/messages-chat-pagination-changes-sol-6-1.html and a 133-line JSON log are in the frontend diff. They do not belong on the hotfix.
The sidebar imports INBOX_TABS from the messages module and GETs the inbox whenever the profile block loads, so the badge can move while you are on another page. That GET swallows errors. The messages page also refetches on every open. Two refreshes, and one of them resets the list.
The writeup says 26 checks passed on the dev server and 12 method checks passed. Live staging on the supplied creator was an empty inbox. Populated history, a non-zero unread change, and a fan login are still on that PR's own checklist.
Lift two fixes onto 10895
getUserChatLogs stores its second argument as the search key. Callers that still pass '' wipe an active search. A socket message, a block, and a delete all do that today. 10896 passes this.inboxSearchKey at those sites. Take that.
Search is still keyup. 10896 uses input, so a paste is included. Take that too.
Leave the rest. The sidebar GET, the inbox reload on open, the broadcast validation flag, and the docs files are the reasons 10896 loses.
What I did not run
- I read
802f734e5a4candaf7fcdb53bc3against the hotfix on 6 October 2026. GitHub reports both as mergeable. Neither has a check run. - I did not boot either branch for this pass. The Jon Snow notes are from the earlier session on 10895. Cursors on that account were all null.
- Still unseen on a real account for 10895: an inbox next page, a history next page, a non-zero pill, a fan
tab=all, broadcast history, and an unread row dropping the pill.
After 10895 merges, use an account with a non-null cursor. Scroll the left list, scroll a long thread, open an unread row, and open a message list. The message list POST should have from and no include_validation.