feat(desktop,service,features): show reactions in the Pull request tab's Conversation
C2 of the "Conversation filters and reactions" stack. It builds on C1 (#3258, merged) and targets main.
What
Emoji reactions now show under the PR description, every comment and review, and every review thread comment, the way GitHub shows them. Each reaction someone gave is a pill with its emoji and count, in GitHub's order (๐ ๐ ๐ ๐ ๐ โค๏ธ ๐ ๐). Hovering a pill shows who gave it, using the same names as the rest of the conversation, with the reader as "You".
The member's own reactions are highlighted, but only when the read actually names the member among the reactors (see below).
This PR only reads reactions. Adding and removing a reaction comes in C3, through the shared "writes as the member" seam (W1).
How reactions are read
-
No extra requests. The conversation read already makes one GraphQL request for review threads. That same request now also asks for
reactionGroupson:- the pull request itself (for the description),
- its newest 100 comments and newest 100 reviews (
comments(last:100)/reviews(last:100), matched to the REST entries bydatabaseId), - every thread comment.
The 100 bound matches the conversation's bound on entries, so every entry the conversation keeps is covered.
-
viewerHasReactedis not used. The overview reads on the GitHub App's token, soviewerHasReacteddescribes the App's bot, not the member. Instead,reactors(first: 10)names up to ten people per reaction. They are matched to workspace members through the existing GitHub-id link (github-people.ts), and a pill is highlighted when the reader is among them. -
Thread comments get counts only. A thread comment's reactions carry
reactors { totalCount }, with no names. I measured the query's GraphQL rate-limit cost: naming reactors under every thread comment raises it from 3 points to 53, because GitHub prices each nested list it might return. As a result:- a thread comment's reactions are never highlighted,
- their tooltip gives only a count ("3 reacted with ๐"),
- a reaction with more than ten people that doesn't list the member is not highlighted either.
C3 is meant to bring highlights back on thread comments by reading the member's own reactions through W1's member-token seam.
-
If the GraphQL read fails, the reactions and threads are left out, as before, and the rest of the conversation still shows.
Wire
New fields:
REACTION,ReactionGroup, andOVERVIEW_BOUNDS.MAX_REACTORS(10).- An optional
reactionson conversation entries and on review-thread comments. - An optional
descriptionReactionson the conversation answer.
Each field is left out when nothing was given, so a response from an older service and one with no reactions look the same. The two coding-agent-*-codingAgentOverviewConversationAnswer*Schema.json goldens were re-recorded with LUKE_UPDATE_FIXTURES=1. Their only change is the new optional reactions / descriptionReactions schema.
Screenshots
Reactions under the description, a review, a thread comment (count only) and a comment, with the reader's own highlighted. Below it, the tooltip (fake data from a throwaway harness):

Tests
pull-request-overview.test.ts: reactions on the description, a comment, a review and a thread comment all come from the one GraphQL request, in GitHub's order, only the ones given, with reactors named. A thread comment's reactions are counted only.agent-pull-request-tab.test.ts: the pills, their tooltips, and the highlight, which shows only when the read names the reader.
pnpm check:affected ran out of memory here, so I ran the per-package checks instead: tsc for desktop, service and features; vitest for features, service github and desktop tasks (1379 tests); ./scripts/oxlint.sh; pnpm knip; ./scripts/repository-checks.sh; and pnpm discarded-effect. All pass.
Made with Luke
Summary by cubic
Shows emoji reactions in the Pull request tab's Conversation, drawn under the PR description, every comment and review, and every review thread comment as GitHub draws them: a pill per reaction with its emoji and count in GitHub's order. Hovering a pill names who reacted using the conversation's names, with the reader as "You", and the reader's own reactions are highlighted where the read names them.
- Reactions come from the one GraphQL ask the conversation already makes for review threads, so no extra requests are made.
- Thread comments' reactions carry counts only โ no names and no highlight โ because naming reactors under every thread comment raises that read's rate-limit cost from 3 points to 53.
- A kept comment the GraphQL read misses (its newest 100 count empty entries) is counted by the rollup its REST listing carries, without names.
- The pills draw in the shared
--luke-*tokens (the compatibility aliases they previously read were removed frommain). - This change only reads reactions; adding and removing them comes in a later step.