Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .roo/rules-pr-fixer/1_workflow.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@
</steps>
</phase>

<phase name="resolve-threads">
<description>After pushing fixes, resolve the review threads on GitHub that have been addressed. This provides clear signal to reviewers that their feedback was acted on.</description>
<steps>
<step>Fetch all review threads for the PR using the GraphQL API: 'gh api graphql' with the pullRequest.reviewThreads query.</step>
<step>For each unresolved thread, determine if the corresponding feedback has been addressed by the code changes just pushed.</step>
<step>Resolve each addressed thread using the GraphQL 'resolveReviewThread' mutation with the thread's node ID.</step>
<step>Leave threads unresolved if they represent open questions, future work, or feedback that was intentionally not addressed.</step>
</steps>
</phase>

<phase name="validation">
<description>Verify that the pushed changes resolve the issues.</description>
<steps>
Expand All @@ -68,6 +78,7 @@

<completion_criteria>
<criterion>All actionable review comments have been addressed.</criterion>
<criterion>Addressed review threads have been resolved on GitHub using the GraphQL API.</criterion>
<criterion>All tests are passing.</criterion>
<criterion>The PR is free of merge conflicts.</criterion>
<criterion>All required translations have been completed and committed (if changes affect user-facing content).</criterion>
Expand Down
11 changes: 11 additions & 0 deletions .roo/rules-pr-fixer/2_best_practices.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@
<item>Verify .gitignore is properly configured</item>
</checklist>
</principle>
<principle priority="high">
<name>Resolve Review Threads, Don't Just Check Boxes</name>
<description>After addressing review feedback and pushing changes, resolve the corresponding review threads on GitHub using the GraphQL API. This provides clear signal to reviewers that their feedback was acted on and keeps the PR review state clean.</description>
<rationale>Checking off internal checklists is not visible to reviewers. Resolving threads on GitHub is the standard way to communicate that feedback has been addressed, and it declutters the review interface.</rationale>
<example>
<scenario>Review comment asking to rename a variable was addressed</scenario>
<good>Fetch review threads via GraphQL, find the matching thread, resolve it with the resolveReviewThread mutation</good>
<bad>Only check off an internal checkbox or leave a reply comment without resolving the thread</bad>
</example>
</principle>
</general_principles>

<code_conventions>
Expand Down Expand Up @@ -67,6 +77,7 @@ This ensures consistent and intelligent conflict resolution across all PRs.
<quality_checklist>
<category name="before_completion">
<item>Have all review comments been addressed?</item>
<item>Have addressed review threads been resolved on GitHub via the GraphQL API?</item>
<item>Are all CI/CD checks passing?</item>
<item>Is the PR free of merge conflicts?</item>
<item>Have the changes been tested locally?</item>
Expand Down
86 changes: 86 additions & 0 deletions .roo/rules-pr-fixer/3_common_patterns.xml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,92 @@
<command tool="git">git commit -m "<commit_message>"</command>
</template>
</pattern>
<pattern name="fetch_review_threads">
<usage>Fetch all review threads for a PR using the GitHub GraphQL API. This returns each thread's node ID, resolution status, and the first comment's body/path/line for context.</usage>
<template>
<command tool="gh"><![CDATA[gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
comments(first: 1) {
nodes {
body
path
line
}
}
}
}
}
}
}' -f owner=<owner> -f repo=<repo> -F number=<pr_number>]]></command>
<comment>Parse the JSON output to get each thread's id (node ID) and isResolved status.</comment>
<comment>Only threads where isResolved is false need to be resolved.</comment>
</template>
</pattern>

<pattern name="resolve_review_thread">
<usage>Resolve a single review thread on GitHub using its node ID via the GraphQL API. Use this after addressing the feedback in the thread.</usage>
<template>
<command tool="gh"><![CDATA[gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread {
id
isResolved
}
}
}' -f threadId=<thread_node_id>]]></command>
<comment>Replace thread_node_id with the actual node ID from the fetch_review_threads query.</comment>
<comment>Only resolve threads whose feedback has actually been addressed in code.</comment>
</template>
</pattern>

<pattern name="resolve_all_addressed_threads">
<usage>End-to-end pattern: fetch all unresolved review threads, then resolve each one that was addressed.</usage>
<template>
<comment>Step 1: Fetch all review threads</comment>
<command tool="gh"><![CDATA[gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
comments(first: 1) {
nodes {
body
path
line
}
}
}
}
}
}
}' -f owner=<owner> -f repo=<repo> -F number=<pr_number>]]></command>
<comment>Step 2: For each unresolved thread (isResolved: false), check if the feedback was addressed</comment>
<comment>Step 3: Resolve each addressed thread individually</comment>
<command tool="gh"><![CDATA[gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread {
id
isResolved
}
}
}' -f threadId=<thread_node_id>]]></command>
<comment>Repeat step 3 for each addressed thread. Do NOT resolve threads for open questions or unaddressed feedback.</comment>
</template>
</pattern>

<pattern name="safe_file_staging">
<usage>Safely stage files for commit while avoiding temporary files and respecting .gitignore.</usage>
<template>
Expand Down
49 changes: 49 additions & 0 deletions .roo/rules-pr-fixer/4_tool_usage.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,50 @@
</best_practices>
</tool>

<tool name="gh api graphql (resolve review threads)">
<best_practices>
<practice>After pushing code changes that address review feedback, use the GraphQL API to resolve the corresponding review threads on GitHub.</practice>
<practice>First fetch all review threads: use the pullRequest.reviewThreads query to get each thread's node ID, isResolved status, and the first comment for context.</practice>
<practice>Only resolve threads where the feedback has actually been addressed in the pushed code changes. Do not resolve threads for open questions, future work items, or feedback that was intentionally skipped.</practice>
<practice>Resolve threads one at a time using the resolveReviewThread mutation with the thread's node ID.</practice>
<practice>If a thread is already resolved (isResolved: true) or outdated (isOutdated: true), skip it.</practice>
</best_practices>
<fetch_threads_query><![CDATA[
gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
comments(first: 1) {
nodes {
body
path
line
}
}
}
}
}
}
}' -f owner=[owner] -f repo=[repo] -F number=[pr_number]
]]></fetch_threads_query>
<resolve_thread_mutation><![CDATA[
gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread {
id
isResolved
}
}
}' -f threadId=[thread_node_id]
]]></resolve_thread_mutation>
</tool>

<tool name="ask_followup_question">
<best_practices>
<practice>After analyzing all the problems (reviews, tests, conflicts), present a summary to the user.</practice>
Expand Down Expand Up @@ -152,5 +196,10 @@ Please ensure all supported languages (ca, de, es, fr, hi, id, it, ja, ko, nl, p
<command>gh run view [RUN_ID] --repo [owner]/[repo] --log-failed</command>
<command>gh workflow view [WORKFLOW_NAME] --repo [owner]/[repo]</command>
</command_group>

<command_group name="review_thread_operations">
<command>gh api graphql -f query='query { repository(owner:"[owner]", name:"[repo]") { pullRequest(number:[PR_NUMBER]) { reviewThreads(first:100) { nodes { id isResolved isOutdated comments(first:1) { nodes { body path line } } } } } } }'</command>
<command>gh api graphql -f query='mutation { resolveReviewThread(input:{threadId:"[THREAD_NODE_ID]"}) { thread { id isResolved } } }'</command>
</command_group>
Comment on lines +200 to +203
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The review_thread_operations command group uses inline/hardcoded values in the GraphQL query string (e.g., owner:"[owner]"), while every other GraphQL example in this PR -- including the fetch_threads_query and resolve_thread_mutation elements in this same file -- uses parameterized GraphQL variables with -f/-F flags. The parameterized approach handles type coercion properly (-F for Int), avoids shell quoting pitfalls, and is the gh CLI's recommended pattern. Having both styles in the same file could lead the agent to copy the less robust inline approach from this quick-reference section.

Suggested change
<command_group name="review_thread_operations">
<command>gh api graphql -f query='query { repository(owner:"[owner]", name:"[repo]") { pullRequest(number:[PR_NUMBER]) { reviewThreads(first:100) { nodes { id isResolved isOutdated comments(first:1) { nodes { body path line } } } } } } }'</command>
<command>gh api graphql -f query='mutation { resolveReviewThread(input:{threadId:"[THREAD_NODE_ID]"}) { thread { id isResolved } } }'</command>
</command_group>
<command_group name="review_thread_operations">
<command>gh api graphql -f query='query($owner: String!, $repo: String!, $number: Int!) { repository(owner: $owner, name: $repo) { pullRequest(number: $number) { reviewThreads(first:100) { nodes { id isResolved isOutdated comments(first:1) { nodes { body path line } } } } } } }' -f owner=[OWNER] -f repo=[REPO] -F number=[PR_NUMBER]</command>
<command>gh api graphql -f query='mutation($threadId: ID!) { resolveReviewThread(input: {threadId: $threadId}) { thread { id isResolved } } }' -f threadId=[THREAD_NODE_ID]</command>
</command_group>

Fix it with Roo Code or mention @roomote and request a fix.

</github_cli_reference>
</tool_usage_guide>
49 changes: 49 additions & 0 deletions .roo/rules-pr-fixer/5_examples.xml
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,61 @@
</tool_use>
<analysis>Monitor checks continuously until all complete. The --watch flag provides real-time updates as check statuses change.</analysis>
</step>

<step number="7">
<description>Fetch all review threads to find unresolved ones that were addressed.</description>
<tool_use>
<execute_command>
<command><![CDATA[gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
repository(owner: $owner, name: $repo) {
pullRequest(number: $number) {
reviewThreads(first: 100) {
nodes {
id
isResolved
isOutdated
comments(first: 1) {
nodes {
body
path
line
}
}
}
}
}
}
}' -f owner=RooCodeInc -f repo=Roo-Code -F number=4365]]></command>
</execute_command>
</tool_use>
<analysis>Parse the output to identify unresolved threads. Match each thread's comment body and file path against the changes we just pushed to determine which threads were addressed.</analysis>
</step>

<step number="8">
<description>Resolve each addressed review thread using the GraphQL mutation.</description>
<tool_use>
<execute_command>
<command><![CDATA[gh api graphql -f query='
mutation($threadId: ID!) {
resolveReviewThread(input: {threadId: $threadId}) {
thread {
id
isResolved
}
}
}' -f threadId=PRT_kwDOExample123]]></command>
</execute_command>
</tool_use>
<analysis>Repeat for each thread that was addressed. Only resolve threads where the feedback was acted on. Leave threads unresolved if they are open questions or were intentionally not addressed.</analysis>
</step>
</workflow>

<key_takeaways>
<takeaway>Always gather all information before proposing a solution.</takeaway>
<takeaway>Use the GitHub CLI to get a complete picture of the PR's status.</takeaway>
<takeaway>The --watch flag on gh pr checks provides real-time monitoring of CI status.</takeaway>
<takeaway>After addressing review feedback, resolve the corresponding review threads on GitHub using the GraphQL API instead of just checking off checkboxes.</takeaway>
</key_takeaways>
</example>

Expand Down
Loading