Describe the bug
Opening a thread with many replies on the mobile app lands at the top of the thread — the user has to scroll all the way down to reach the newest reply. The desktop thread panel opens scrolled to the bottom (newest message), so the two clients disagree on where a thread opens.
To reproduce
- On mobile, open a channel and tap into a thread whose replies overflow the screen (say 20+ replies).
- The view shows the thread head at the top; the newest replies are below the fold.
- Same thread on desktop: the panel opens pinned to the newest message.
Expected behavior
Mobile matches desktop: opening a thread lands on the newest reply (with short threads still showing the head at the top).
Mechanism (as of 28ae6cd)
This looks like a deliberate-layout change that completed only half of desktop's behavior — said with respect, since the current behavior is clearly chosen, not accidental: #3485 converted the thread list from reverse: true to top-anchored (fixing short threads jamming the head against the composer) and pinned the head-visible hydration with a named test. Its in-code comment says the layout matches "desktop's thread panel" — and it does match desktop's DOM order, but desktop pairs that top-down layout with an explicit bottom-pin on open: useAnchoredScroll's pinToBottomOnMount() (desktop/src/features/messages/ui/useAnchoredScroll.ts) scrolls to scrollHeight when the thread panel initializes, with a deep-link target taking precedence and a missed target falling back to the bottom-pin.
Mobile's thread_detail_page.dart performs no initial scroll unless initialMessageId is set — the hydration effect explicitly establishes its baseline "without moving the user away from the head". The earlier fix for this exact symptom (#1499, reversed list) was superseded by #3485's redesign.
So the parity claim is incomplete rather than wrong: top-down layout ✔, open-at-latest ✘.
Fix
PR incoming from this account: keep #3485's top-anchored layout (short threads keep the head at top), add a one-shot initial pin to the newest reply mirroring desktop's precedence (resolvable deep-link target wins; missed target falls back to the pin; a user who scrolled during a slow hydration is never overridden), widget tests included — the head-visible hydration test is flipped to the completed contract.
Describe the bug
Opening a thread with many replies on the mobile app lands at the top of the thread — the user has to scroll all the way down to reach the newest reply. The desktop thread panel opens scrolled to the bottom (newest message), so the two clients disagree on where a thread opens.
To reproduce
Expected behavior
Mobile matches desktop: opening a thread lands on the newest reply (with short threads still showing the head at the top).
Mechanism (as of
28ae6cd)This looks like a deliberate-layout change that completed only half of desktop's behavior — said with respect, since the current behavior is clearly chosen, not accidental: #3485 converted the thread list from
reverse: trueto top-anchored (fixing short threads jamming the head against the composer) and pinned the head-visible hydration with a named test. Its in-code comment says the layout matches "desktop's thread panel" — and it does match desktop's DOM order, but desktop pairs that top-down layout with an explicit bottom-pin on open:useAnchoredScroll'spinToBottomOnMount()(desktop/src/features/messages/ui/useAnchoredScroll.ts) scrolls toscrollHeightwhen the thread panel initializes, with a deep-link target taking precedence and a missed target falling back to the bottom-pin.Mobile's
thread_detail_page.dartperforms no initial scroll unlessinitialMessageIdis set — the hydration effect explicitly establishes its baseline "without moving the user away from the head". The earlier fix for this exact symptom (#1499, reversed list) was superseded by #3485's redesign.So the parity claim is incomplete rather than wrong: top-down layout ✔, open-at-latest ✘.
Fix
PR incoming from this account: keep #3485's top-anchored layout (short threads keep the head at top), add a one-shot initial pin to the newest reply mirroring desktop's precedence (resolvable deep-link target wins; missed target falls back to the pin; a user who scrolled during a slow hydration is never overridden), widget tests included — the head-visible hydration test is flipped to the completed contract.