@@ -10,18 +10,19 @@ 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
13+ ## Required Unresolved-Batch Query
1414
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.
15+ Use this command exactly as written for metadata-first traversal across
16+ review-thread pages until it collects the first 10 unresolved threads. The 10
17+ unresolved items may be sparse, non-contiguous, and spread across multiple
18+ pages. After that metadata pass, fetch narrow details only for that unresolved
19+ batch. Do not rewrite, broaden, or replace it with an equivalent query.
1920
2021If this command fails for any reason, stop and report the failure explicitly
2122before taking any further review-handling action.
2223
2324``` 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+ deno eval 'const o="OWNER",r="REPO",n="PR_NUMBER",maxUnresolved=10,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={pageInfo:{hasNextPage:false,endCursor:null},nodes:[]},u=[];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;for(const node of t.nodes){if(!node.isResolved)u.push(node);if(u.length===maxUnresolved)break}if(u.length===maxUnresolved||!t.pageInfo.hasNextPage)break;a=t.pageInfo.endCursor}const ids=u.slice(0,maxUnresolved).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,batchSize:ids.length,exhausted:!t.pageInfo.hasNextPage&&ids.length<maxUnresolved,unresolved:d.length?d:u.slice(0,maxUnresolved)}))'
2526```
2627
2728## Workflow
@@ -35,17 +36,21 @@ deno eval 'const o="OWNER",r="REPO",n="PR_NUMBER",mq="query($o:String!,$r:String
3536 - Use GraphQL ` reviewThreads ` as the source of truth for unresolved state;
3637 REST review comments do not expose thread resolution and cannot be filtered
3738 to unresolved-only.
38- - Run the required latest-page query command exactly as written in
39- ` Required Latest-Page Query ` .
39+ - Run the required unresolved-batch query command exactly as written in
40+ ` Required Unresolved-Batch Query ` .
4041 - If the command fails, stop and report the failure explicitly.
4142 - Keep GraphQL payloads narrow: request small pages (` first: 20 ` or similar)
4243 and fetch only thread metadata first (` id ` , ` isResolved ` , ` isOutdated ` ,
4344 ` path ` , ` pageInfo ` ) while paginating. Do not request full comment bodies
4445 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.
46+ - Traverse metadata pages sequentially until you either collect 10 unresolved
47+ threads or exhaust pagination.
48+ - Expect unresolved threads to be sparse and split across multiple pages; do
49+ not assume they are contiguous on one page.
50+ - If unresolved items are found, run a second narrow GraphQL query only for
51+ those unresolved thread IDs in the current batch to fetch review contents.
52+ - Re-run the same query after resolving a batch so the protocol can process
53+ the next 10 unresolved items in a pseudo while loop until none remain.
4954 - If you need latest-first lightweight browsing, use REST review comments as
5055 a secondary view (` /pulls/{number}/comments?sort=updated&direction=desc ` ),
5156 but do not use REST as the authoritative unresolved-thread source.
0 commit comments