@@ -10,6 +10,20 @@ request and review feedback needs to be handled systematically.
1010- keep fixes narrow and scoped to the verified issue
1111- resolve handled review threads and request a fresh review cycle
1212
13+ ## Required Latest-Page Query
14+
15+ Use this command exactly as written for metadata-first traversal to the latest
16+ review-thread page, followed by a narrow detail fetch only for unresolved
17+ threads found on that last page. Do not rewrite, broaden, or replace it with an
18+ equivalent query.
19+
20+ If this command fails for any reason, stop and report the failure explicitly
21+ before taking any further review-handling action.
22+
23+ ``` bash
24+ deno eval 'const o="OWNER",r="REPO",n="PR_NUMBER",mq="query($o:String!,$r:String!,$n:Int!,$a:String){repository(owner:$o,name:$r){pullRequest(number:$n){reviewThreads(first:20,after:$a){pageInfo{hasNextPage endCursor}nodes{id isResolved isOutdated path}}}}}",dq="query($ids:[ID!]!){nodes(ids:$ids){... on PullRequestReviewThread{id path isResolved isOutdated comments(first:10){nodes{author{login}body url createdAt}}}}}";let a=null,t;for(;;){const c=new Deno.Command("gh",{args:["api","graphql","-f",`query=${mq}`,"-F",`o=${o}`,"-F",`r=${r}`,"-F",`n=${n}`,...(a?["-F",`a=${a}`]:[])]});const x=await c.output();if(!x.success){console.error(new TextDecoder().decode(x.stderr));Deno.exit(x.code)}t=JSON.parse(new TextDecoder().decode(x.stdout)).data.repository.pullRequest.reviewThreads;if(!t.pageInfo.hasNextPage)break;a=t.pageInfo.endCursor}const u=t.nodes.filter(x=>!x.isResolved),ids=u.map(x=>x.id);let d=[];if(ids.length){const c=new Deno.Command("gh",{args:["api","graphql","-f",`query=${dq}`,...ids.flatMap(id=>["-F",`ids[]=${id}`])]});const x=await c.output();if(!x.success){console.error(new TextDecoder().decode(x.stderr));Deno.exit(x.code)}d=JSON.parse(new TextDecoder().decode(x.stdout)).data.nodes.filter(Boolean)}console.log(JSON.stringify({pageInfo:t.pageInfo,unresolved:d.length?d:u}))'
25+ ```
26+
1327## Workflow
1428
15291 . Detect the active PR.
@@ -21,22 +35,20 @@ request and review feedback needs to be handled systematically.
2135 - Use GraphQL ` reviewThreads ` as the source of truth for unresolved state;
2236 REST review comments do not expose thread resolution and cannot be filtered
2337 to unresolved-only.
38+ - Run the required latest-page query command exactly as written in
39+ ` Required Latest-Page Query ` .
40+ - If the command fails, stop and report the failure explicitly.
2441 - Keep GraphQL payloads narrow: request small pages (` first: 20 ` or similar)
2542 and fetch only thread metadata first (` id ` , ` isResolved ` , ` isOutdated ` ,
26- ` path ` , ` pageInfo ` ). Do not request full comment bodies for every thread in
27- the first pass.
28- - Filter unresolved threads locally from that metadata page set, then run a
29- second narrow GraphQL query only for the unresolved thread IDs you still
30- need details for.
43+ ` path ` , ` pageInfo ` ) while paginating. Do not request full comment bodies
44+ for every thread in the first pass.
45+ - Traverse metadata pages sequentially until you reach the latest page, then
46+ filter unresolved threads locally from that latest page result.
47+ - If unresolved items are found there, run a second narrow GraphQL query only
48+ for those unresolved thread IDs to fetch review contents.
3149 - If you need latest-first lightweight browsing, use REST review comments as
3250 a secondary view (` /pulls/{number}/comments?sort=updated&direction=desc ` ),
3351 but do not use REST as the authoritative unresolved-thread source.
34- - Minified unresolved-only page pattern:
35- `gh api graphql -f query='query($o: String !,$r: String !,$n: Int !,$a: String ){repository(owner:$o,name:$r){pullRequest(number:$n){reviewThreads(first:20,after:$a){pageInfo{hasNextPage endCursor}nodes{id isResolved isOutdated path}}}}}' -F o=OWNER -F r=REPO -F n=PR_NUMBER > /tmp/review-page.json && python3 - <<'PY'
36- import json
37- with open('/tmp/review-page.json') as f: t =json.load(f)[ 'data'] [ 'repository' ] [ 'pullRequest'] [ 'reviewThreads' ]
38- print(json.dumps({'pageInfo': t [ 'pageInfo'] ,'unresolved':[ x for x in t[ 'nodes'] if not x[ 'isResolved']] },separators=(',',':')))
39- PY`
4052 - Normalize unresolved items into discrete review claims with:
4153 - thread id
4254 - file/path
0 commit comments