A write to a thread or comment now reads, in the head check, the pull
request that holds it and is refused without a mutation when that is
another pull request. Submitting the pending review keeps the
submission to reconcile, so an unknown outcome blocks a second review.
GraphQL errors count as refusals only when every type names one, so a
GitHub timeout reports an unknown outcome. Pending reviews are found
by viewerDidAuthor among up to 100, without the unused commit field. A
resolved thread stays open while the reader writes in it, unsupported
writes no longer poll, and the docs state the partial two-step write.
- A jump to a thread centered its card on every later jump to the same file, since the jump target outlived the jump.
The scroll target now carries the card to center and is cleared when the jump ends; unfolding still follows the
latest thread jump.
- In a commit range view, a thread on a file the chosen commits do not change opened on the host instead of choosing
all commits; a thread the chosen commits do not hold now always chooses all commits first.
- A quote of an old-side thread named the head as the commit its lines number. It now says the lines number the file
before the change and names the head only as where the diff ends, and ForgeAnchor documents the same.
- Refresh reads review threads from the host past the panel's cache (`changeRequestReview` takes `fresh`), so a thread
resolved since shows without waiting for `reviewRefreshMs`; `maxCachedReviewBytes` defaults to 16 MiB, at least
one read under forge-github's default `maxOutputBytes`.
- Picking a thread from a list that covers the files moves the focus to the thread's card.
- `ForgeReviewData.viewer`, its GraphQL field, `ThreadActions.viewer`, and `ThreadReadState.unsupported` had no
consumer and are removed.
- A quoted outdated thread is named by the lines it was written on; a missing pull request or repository makes a
review read `not-found`; a truncated read that kept no thread still offers the thread list.
ForgeProvider gains an optional writeReview for replies, resolution,
comment edits and deletions, and the viewer's pending review, which
review reads now report with the viewer's permissions. The GitHub
provider checks the head and the pending review in one query, then
sends one GraphQL mutation on stdin and never retries it; a reply at
once is refused while a pending review exists, since GitHub adds it
to that review. The forge panel Remote changeRequestReviewWrite drops
the kept threads after every write, because resolving a thread does
not move a pull request's updatedAt.
A first review thread page whose output alone passes maxOutputBytes fails the read as too-large through gh's output
limit, rather than ending it as truncated as the README and the ReviewLimits documentation said; only a later page
that would pass the limit truncates the read. Thread pages after the first re-check the head, while a thread's comment
pages do not. A test pins the first-page failure.
ForgeProvider gains the optional readReview(ref, headSha, signal), which
returns ForgeReviewData only when the read names headSha as the head and
a stale failure otherwise. Each thread carries a current position on the
head and the original position it was written at; ForgeFailure gains the
unsupported code that ctx.forge.readReview returns for a provider
without review reads.
forge-github reads the threads, the head, and the viewer in one GraphQL
query, pages threads up to maxReviewThreads and comments to their end,
re-checks the head on every following thread page, and bounds all pages
by maxOutputBytes. A thread is placed at the head only when GitHub keeps
it current and its first comment is on the head commit.
The forge panel adds the changeRequestReview Remote, cached per change
request by head and update time and read again after reviewRefreshMs,
since resolving a thread does not change a pull request's updatedAt.