fix: recognize resolved GitHub review threads in summary#125
Conversation
GitHub's REST comment endpoints omit thread-resolution state, so every prior thread looked open. The summary carry-over and prior-thread context therefore kept re-listing findings that had already been resolved. Read resolution from the GraphQL `reviewThreads` API and stamp it onto the normalized notes (`resolved`), mirroring GitLab's per-note field so the shared `notes.some((n) => n.resolved)` checks work on both platforms. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Code ReviewRisk: Low — The change appears to address the GitHub resolved-thread carry-over bug without introducing blocking defects, so it is safe to merge. This MR adds a GitHub GraphQL read path for resolved review-thread state, threads that data through discussion normalization, and reuses the existing shared carry-over / prior-thread helpers via the normalized Review usage: 260,877 in (210,432 cached) / 5,466 out tokens — $0.2607 (cloudflare-ai-gateway/gpt-5.4, thinking: medium) Reviewed by @weareikko/code-review v0.8.2 for commit 02a810c. |
Problem
On GitHub PRs, the review summary keeps re-listing findings in its "Still open from earlier reviews" block even after the human has resolved those threads (observed on studiometa/ui#511, where all 15 bot threads were resolved yet still appeared as open). The reviewer also re-raises already-settled concerns.
Root cause
Both summary paths decide resolution with
notes.some((n) => n.resolved === true):src/summary-carryover.ts— skips resolved threads when building the carry-over block.src/prior-threads.ts— flags a prior threadresolvedfor the reviewer prompt.But on GitHub
note.resolvedwas alwaysundefined:normalizeGitHubDiscussionsnever set it.getDiscussionsreads the REST endpointsGET /pulls/{n}/commentsandGET /issues/{n}/comments, and neither REST endpoint returns thread-resolution state. On GitHub, review-thread resolution lives only in the GraphQL API (pullRequest.reviewThreads.nodes.isResolved).So every prior thread looked open: resolved findings were carried over indefinitely, and resolved concerns were re-raised. This works on GitLab because its discussions API returns
resolvedper note inline.Fix
GitHubClient.listResolvedReviewCommentIds()— paginated GraphQLreviewThreadsquery returning the database ids of comments in resolved threads. Derives the GraphQL endpoint from the REST base (github.com →/graphql; GHE/api/v3→/api/graphql) and surfaces GraphQL errors as typedGitHubApiErrors with an actionable hint.getDiscussionsfetches resolution alongside the two REST calls and passes it tonormalizeGitHubDiscussions, which stampsresolvedonto each note — mirroring GitLab's per-note field so the shared helpers work unchanged on both platforms.Tests
github.test.ts: resolved-id extraction, GHE endpoint, thread pagination, typed error on GraphQLerrors.platforms/github.test.ts: notes flagged resolved by id; default-unresolved; end-to-endgetDiscussions→ carry-over exclusion.cli.integration.test.ts: in-memory backend now models resolution via GraphQL; new test asserts a resolved prior finding is dropped from the summary (reproduces #511), while the existing unresolved-carry-over test still passes.npm run checkpasses (lint, format, typecheck, typecheck:tests, 696 tests, build).🤖 Generated with Claude Code