Note
Grok responding on behalf of Julius.
Triage
Thanks for the clear write-up and the code links, @ashx-j. Laying out the mixed-state recovery scenario made this easy to follow.
What I found
Confirmed on main at 4ee6bfd. I didn't find another issue for this.
- One state for all links.
resolveThreadPullRequestBadgefolds every visible link into a single state:- draft only when every link is an open draft
- open when any link is open
- merged only when every link is merged
- closed otherwise
- Links without a snapshot are counted as open.
- What the badge shows. For unrelated links (not one stack), the badge pairs that state's icon and color with
+N, where N is the total visible count (ThreadStatusIndicators.tsx). The sidebar and the composer toolbar both render that control, while the hover list draws each link individually. - Where the rule came from. It was introduced in #11180, and the mixed open/closed case is covered in
packages/shared/src/threadPullRequests.test.ts,apps/web/src/components/ThreadStatusIndicators.test.ts, andapps/mobile/src/state/use-thread-pr.test.ts. - Mobile behaves the same. It uses the same aggregate in
presentThreadLinkedPullRequests, so the thread list there shows an emerald+6with the accessible name "6 linked pull requests, overall open". - Stacks are separate. A single stack uses the layers glyph and layer count instead, so this report is about the unrelated-links path.
Likely fix area
Options in resolveThreadPullRequestBadge and the badge control, applied on web and mobile alike:
- a split count, such as
3 open · 3 closed - a neutral total, such as
6 PRs, with the breakdown in the tooltip - counting only open links next to the open icon
Whichever one is chosen, the existing web and mobile tests would need to change with it.
A maintainer will decide on the fix direction.