From fc493bafbd25be7c635054dab685c623026e2c3c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:04:31 +0000
Subject: [PATCH 1/2] Update pr sous-chef heuristics for nudges and
review-thread resolution
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/pr-sous-chef.lock.yml | 44 ++++++++++++-------
.github/workflows/pr-sous-chef.md | 44 ++++++++++++++-----
.../pr_sous_chef_workflow_contract_test.go | 7 ++-
3 files changed, 66 insertions(+), 29 deletions(-)
diff --git a/.github/workflows/pr-sous-chef.lock.yml b/.github/workflows/pr-sous-chef.lock.yml
index d10c151c351..a82bdfde48e 100644
--- a/.github/workflows/pr-sous-chef.lock.yml
+++ b/.github/workflows/pr-sous-chef.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"64e4ac44d478d1ff1d5cbaa050f7412ea0a0745218ebd4910d2e0d68ae2e3696","body_hash":"7789d855cf7ad1e35be8d5cdff757761bdb06bddc7ecb843258336d8fbd6c7a9","strict":true,"agent_id":"pi","agent_model":"copilot/gpt-5.4","engine_versions":{"pi":"0.80.3"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"9cd58a3cfd50f2fff17e4ecfa36f3eb1a796c466578fdaf17d1b5974b2ff83b9","body_hash":"fc1357ab0fb8f68b718d5a4a93f046ee1c918ee64aa64cd84cd523d91ce12f89","strict":true,"agent_id":"pi","agent_model":"copilot/gpt-5.4","engine_versions":{"pi":"0.80.3"}}
# gh-aw-manifest: {"version":1,"secrets":["AWI_MAINTENANCE_TOKEN","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"924ae3a1cded613372ab5595356fb5720e22ba16","version":"v6.5.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.29","digest":"sha256:debc0b18ef8ea3a64585c4d1eea1099f0d9fa76b53d34a1f3c53b3225fe158fe","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.29@sha256:debc0b18ef8ea3a64585c4d1eea1099f0d9fa76b53d34a1f3c53b3225fe158fe"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.29","digest":"sha256:c7754df3f06f346c817db0525ba523cbdaf5349239fd7f37897c4250a8fc7bde","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.29@sha256:c7754df3f06f346c817db0525ba523cbdaf5349239fd7f37897c4250a8fc7bde"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.29","digest":"sha256:bfc90b1f10d2ff61dbbbf0d57600001f85bf5f6444ed78bc05d9f6677327e4b8","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.29@sha256:bfc90b1f10d2ff61dbbbf0d57600001f85bf5f6444ed78bc05d9f6677327e4b8"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.29","digest":"sha256:7bfa0742f9a5bd6309507caaa80a8b6cf3e05bd95a1429affbf64cc94cfbd34f","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.29@sha256:7bfa0742f9a5bd6309507caaa80a8b6cf3e05bd95a1429affbf64cc94cfbd34f"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]}
# This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
#
@@ -316,23 +316,23 @@ jobs:
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
- cat << 'GH_AW_PROMPT_1007377445313f3f_EOF'
+ cat << 'GH_AW_PROMPT_09586fda74ac0644_EOF'
- GH_AW_PROMPT_1007377445313f3f_EOF
+ GH_AW_PROMPT_09586fda74ac0644_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
- cat << 'GH_AW_PROMPT_1007377445313f3f_EOF'
+ cat << 'GH_AW_PROMPT_09586fda74ac0644_EOF'
- Tools: add_comment(max:20), create_issue, update_pull_request(max:10), dismiss_pull_request_review(max:20), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop
- GH_AW_PROMPT_1007377445313f3f_EOF
+ Tools: add_comment(max:4), create_issue, update_pull_request(max:10), dismiss_pull_request_review(max:20), resolve_pull_request_review_thread(max:40), push_to_pull_request_branch(max:10), missing_tool, missing_data, noop
+ GH_AW_PROMPT_09586fda74ac0644_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md"
- cat << 'GH_AW_PROMPT_1007377445313f3f_EOF'
+ cat << 'GH_AW_PROMPT_09586fda74ac0644_EOF'
- GH_AW_PROMPT_1007377445313f3f_EOF
+ GH_AW_PROMPT_09586fda74ac0644_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md"
- cat << 'GH_AW_PROMPT_1007377445313f3f_EOF'
+ cat << 'GH_AW_PROMPT_09586fda74ac0644_EOF'
The following GitHub context information is available for this workflow:
{{#if github.actor}}
@@ -374,7 +374,7 @@ jobs:
stop immediately and report the limitation rather than spending turns trying to work around it.
- GH_AW_PROMPT_1007377445313f3f_EOF
+ GH_AW_PROMPT_09586fda74ac0644_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/cli_proxy_with_safeoutputs_prompt.md"
if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_prompt.md"
@@ -382,11 +382,11 @@ jobs:
if [ "$GITHUB_EVENT_NAME" = "issue_comment" ] && [ -n "$GH_AW_IS_PR_COMMENT" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review_comment" ] || [ "$GITHUB_EVENT_NAME" = "pull_request_review" ]; then
cat "${RUNNER_TEMP}/gh-aw/prompts/pr_context_push_to_pr_branch_guidance.md"
fi
- cat << 'GH_AW_PROMPT_1007377445313f3f_EOF'
+ cat << 'GH_AW_PROMPT_09586fda74ac0644_EOF'
{{#runtime-import .github/workflows/shared/otlp.md}}
{{#runtime-import .github/workflows/pr-sous-chef.md}}
- GH_AW_PROMPT_1007377445313f3f_EOF
+ GH_AW_PROMPT_09586fda74ac0644_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
@@ -830,18 +830,19 @@ jobs:
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
- cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_fd43ee3d7dd4e34f_EOF'
- {"add_comment":{"github-token":"${GH_AW_SECRET_AWI_MAINTENANCE_TOKEN}","max":20,"target":"*"},"create_issue":{"close_older_issues":true,"expires":72,"labels":["automation"],"max":1,"title_prefix":"[pr-sous-chef] "},"create_report_incomplete_issue":{},"dismiss_pull_request_review":{"max":20,"target":"*"},"mentions":{"allowed":["copilot"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"commit_title_suffix":" [pr-sous-chef]","excluded_files":[".github/workflows/**"],"if_no_changes":"ignore","max":10,"max_patch_size":4096,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","PI.md","AGENTS.md"],"target":"*"},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"default_operation":"append","max":10,"target":"*","update_branch":true}}
- GH_AW_SAFE_OUTPUTS_CONFIG_fd43ee3d7dd4e34f_EOF
+ cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_fb1d6d2d5c7b3fe7_EOF'
+ {"add_comment":{"github-token":"${GH_AW_SECRET_AWI_MAINTENANCE_TOKEN}","max":4,"target":"*"},"create_issue":{"close_older_issues":true,"expires":72,"labels":["automation"],"max":1,"title_prefix":"[pr-sous-chef] "},"create_report_incomplete_issue":{},"dismiss_pull_request_review":{"max":20,"target":"*"},"mentions":{"allowed":["copilot"]},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"commit_title_suffix":" [pr-sous-chef]","excluded_files":[".github/workflows/**"],"if_no_changes":"ignore","max":10,"max_patch_size":4096,"protect_top_level_dot_folders":true,"protected_files":["package.json","bun.lockb","bunfig.toml","deno.json","deno.jsonc","deno.lock","global.json","NuGet.Config","Directory.Packages.props","mix.exs","mix.lock","go.mod","go.sum","stack.yaml","stack.yaml.lock","pom.xml","build.gradle","build.gradle.kts","settings.gradle","settings.gradle.kts","gradle.properties","package-lock.json","yarn.lock","pnpm-lock.yaml","npm-shrinkwrap.json","requirements.txt","Pipfile","Pipfile.lock","pyproject.toml","setup.py","setup.cfg","Gemfile","Gemfile.lock","uv.lock","CODEOWNERS","DESIGN.md","README.md","CONTRIBUTING.md","CHANGELOG.md","SECURITY.md","CODE_OF_CONDUCT.md","PI.md","AGENTS.md"],"target":"*"},"report_incomplete":{},"resolve_pull_request_review_thread":{"max":40},"update_pull_request":{"allow_body":true,"allow_title":false,"default_operation":"append","max":10,"target":"*","update_branch":true}}
+ GH_AW_SAFE_OUTPUTS_CONFIG_fb1d6d2d5c7b3fe7_EOF
- name: Generate Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
{
"description_suffixes": {
- "add_comment": " CONSTRAINTS: Maximum 20 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.",
+ "add_comment": " CONSTRAINTS: Maximum 4 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.",
"create_issue": " CONSTRAINTS: Maximum 1 issue(s) can be created. Title will be prefixed with \"[pr-sous-chef] \". Labels [\"automation\"] will be automatically added.",
"dismiss_pull_request_review": " CONSTRAINTS: Maximum 20 review dismissal(s) can be performed. Target: *. justification must contain at least 20 characters.",
"push_to_pull_request_branch": " CONSTRAINTS: Maximum 10 push(es) can be made.",
+ "resolve_pull_request_review_thread": " CONSTRAINTS: Maximum 40 review thread(s) can be resolved.",
"update_pull_request": " CONSTRAINTS: Maximum 10 pull request(s) can be updated. Target: *."
},
"repo_params": {},
@@ -1033,6 +1034,15 @@ jobs:
}
}
},
+ "resolve_pull_request_review_thread": {
+ "defaultMax": 10,
+ "fields": {
+ "thread_id": {
+ "required": true,
+ "type": "string"
+ }
+ }
+ },
"update_pull_request": {
"defaultMax": 1,
"fields": {
@@ -2135,7 +2145,7 @@ jobs:
GH_AW_ALLOWED_DOMAINS: "*.grafana.net,*.sentry.io,api.githubcopilot.com,api.pi.ai,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,github.com,go.dev,golang.org,goproxy.io,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,pkg.go.dev,ppa.launchpad.net,proxy.golang.org,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,storage.googleapis.com,sum.golang.org,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com"
GITHUB_SERVER_URL: ${{ github.server_url }}
GITHUB_API_URL: ${{ github.api_url }}
- GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.AWI_MAINTENANCE_TOKEN }}\",\"max\":20,\"target\":\"*\"},\"create_issue\":{\"close_older_issues\":true,\"expires\":72,\"labels\":[\"automation\"],\"max\":1,\"title_prefix\":\"[pr-sous-chef] \"},\"create_report_incomplete_issue\":{},\"dismiss_pull_request_review\":{\"max\":20,\"target\":\"*\"},\"mentions\":{\"allowed\":[\"copilot\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"commit_title_suffix\":\" [pr-sous-chef]\",\"excluded_files\":[\".github/workflows/**\"],\"if_no_changes\":\"ignore\",\"max\":10,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"PI.md\",\"AGENTS.md\"],\"target\":\"*\"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"default_operation\":\"append\",\"max\":10,\"target\":\"*\",\"update_branch\":true}}"
+ GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"github-token\":\"${{ secrets.AWI_MAINTENANCE_TOKEN }}\",\"max\":4,\"target\":\"*\"},\"create_issue\":{\"close_older_issues\":true,\"expires\":72,\"labels\":[\"automation\"],\"max\":1,\"title_prefix\":\"[pr-sous-chef] \"},\"create_report_incomplete_issue\":{},\"dismiss_pull_request_review\":{\"max\":20,\"target\":\"*\"},\"mentions\":{\"allowed\":[\"copilot\"]},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"commit_title_suffix\":\" [pr-sous-chef]\",\"excluded_files\":[\".github/workflows/**\"],\"if_no_changes\":\"ignore\",\"max\":10,\"max_patch_size\":4096,\"protect_top_level_dot_folders\":true,\"protected_files\":[\"package.json\",\"bun.lockb\",\"bunfig.toml\",\"deno.json\",\"deno.jsonc\",\"deno.lock\",\"global.json\",\"NuGet.Config\",\"Directory.Packages.props\",\"mix.exs\",\"mix.lock\",\"go.mod\",\"go.sum\",\"stack.yaml\",\"stack.yaml.lock\",\"pom.xml\",\"build.gradle\",\"build.gradle.kts\",\"settings.gradle\",\"settings.gradle.kts\",\"gradle.properties\",\"package-lock.json\",\"yarn.lock\",\"pnpm-lock.yaml\",\"npm-shrinkwrap.json\",\"requirements.txt\",\"Pipfile\",\"Pipfile.lock\",\"pyproject.toml\",\"setup.py\",\"setup.cfg\",\"Gemfile\",\"Gemfile.lock\",\"uv.lock\",\"CODEOWNERS\",\"DESIGN.md\",\"README.md\",\"CONTRIBUTING.md\",\"CHANGELOG.md\",\"SECURITY.md\",\"CODE_OF_CONDUCT.md\",\"PI.md\",\"AGENTS.md\"],\"target\":\"*\"},\"report_incomplete\":{},\"resolve_pull_request_review_thread\":{\"max\":40},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"default_operation\":\"append\",\"max\":10,\"target\":\"*\",\"update_branch\":true}}"
GH_AW_CI_TRIGGER_TOKEN: ${{ secrets.GH_AW_CI_TRIGGER_TOKEN }}
with:
github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/pr-sous-chef.md b/.github/workflows/pr-sous-chef.md
index 5b0badd93aa..7a281e86dd9 100644
--- a/.github/workflows/pr-sous-chef.md
+++ b/.github/workflows/pr-sous-chef.md
@@ -208,9 +208,11 @@ steps:
run: npm ci --prefix actions/setup/js
safe-outputs:
add-comment:
- max: 20
+ max: 4
target: "*"
github-token: ${{ secrets.AWI_MAINTENANCE_TOKEN }}
+ resolve-pull-request-review-thread:
+ max: 40
dismiss-pull-request-review:
max: 20
target: "*"
@@ -266,12 +268,18 @@ When this workflow is triggered by the `/souschef` slash command on a PR comment
1. Read `/tmp/gh-aw/agent/pr-sous-chef-candidates-compact.json` first.
2. If `prs` is empty, create the run-report issue (see **Run summary** below) and stop. If `create_issue` is unavailable, fall back to `noop` with the message `"processed=0; nudged=0; no eligible PRs"` and stop.
3. Process PRs in `updatedAt` descending order.
-4. Process all eligible PRs per run.
-5. Use the `pr-processor` sub-agent for each PR; pass only the PR number and compact context.
-6. If a `pr-processor` call returns non-JSON or an error, record `{pr_number: , skip_reason: "sub_agent_error"}` in the `skipped` array of the run-summary issue payload and move to the next PR without retrying.
-7. Do not fetch full PR diffs or large file lists unless absolutely required for a skip decision.
-8. **Never finish without at least one safe-output tool call.** Always call the run-summary `create_issue` (see **Run summary** below) before finishing. If `create_issue` is unavailable, fall back to `noop` with a condensed message containing the run counts (see fallback example in **Run summary**).
-9. Use `safeoutputs --param value` shell commands for all safe-output operations (`add_comment`, `update_pull_request`, `push_to_pull_request_branch`, `create_issue`, `noop`, `report_incomplete`). Do **not** use `gh pr comment`, `gh pr update-branch`, `gh api ... -X POST`, or any GitHub API write calls outside of `safeoutputs`. Do **not** pipe `safeoutputs` to other commands or run `safeoutputs --help` — the tool schemas are already provided; use the examples below directly.
+4. Process at most 4 nudges per run.
+5. Prioritize which PRs to nudge, in this order:
+ - `mergeStateStatus == "CONFLICTING"` first (explicit merge-conflict unblock request).
+ - PRs with unresolved review threads where at least one thread already has a follow-up response from the PR author or `@copilot` but remains unresolved.
+ - Remaining PRs by most-recent `updatedAt`.
+ If two PRs are still tied, prioritize the lower PR number first for deterministic behavior.
+6. After applying skip rules, stop creating new nudge comments once 4 PRs have been nudged in the current run. Continue processing only for required bookkeeping/reporting.
+7. Use the `pr-processor` sub-agent for each PR; pass only the PR number and compact context.
+8. If a `pr-processor` call returns non-JSON or an error, record `{pr_number: , skip_reason: "sub_agent_error"}` in the `skipped` array of the run-summary issue payload and move to the next PR without retrying.
+9. Do not fetch full PR diffs or large file lists unless absolutely required for a skip decision.
+10. **Never finish without at least one safe-output tool call.** Always call the run-summary `create_issue` (see **Run summary** below) before finishing. If `create_issue` is unavailable, fall back to `noop` with a condensed message containing the run counts (see fallback example in **Run summary**).
+11. Use `safeoutputs --param value` shell commands for all safe-output operations (`add_comment`, `update_pull_request`, `push_to_pull_request_branch`, `resolve_pull_request_review_thread`, `dismiss_pull_request_review`, `create_issue`, `noop`, `report_incomplete`). Do **not** use `gh pr comment`, `gh pr update-branch`, `gh api ... -X POST`, or any GitHub API write calls outside of `safeoutputs`. Do **not** pipe `safeoutputs` to other commands or run `safeoutputs --help` — the tool schemas are already provided; use the examples below directly.
## Required skip rules per PR
@@ -294,7 +302,7 @@ Before any nudge for a PR:
- Candidate prefilter already removes PRs where the most recent sous-chef comment (containing both the marker and `@copilot`) was posted within the last 30 minutes.
- If any recent comment contains both `` and `@copilot` and was created less than 30 minutes ago, skip this PR. Comments with the marker but without `@copilot` are informational and do **not** trigger the cooldown.
-## Required nudges for eligible PRs
+## Required nudges for prioritized eligible PRs
For each PR that is not skipped:
@@ -337,9 +345,21 @@ For each PR that is not skipped:
safeoutputs add_comment --pr_number 12345 --body $'\n@copilot please run the `pr-finisher` skill, address unresolved review comments, and rerun checks once the branch is up to date.'
```
-3. **Dismiss stale `github-actions[bot]` blocking reviews when all PR review threads are resolved**
+3. **Resolve review threads that already have a response using a safe output**
+ - For `schedule` and `workflow_dispatch` runs, use the `resolve_review_threads` list returned by the `pr-processor` sub-agent.
+ - Include a thread in `resolve_review_threads` only when all of the following are true:
+ - the thread is currently unresolved;
+ - the thread contains reviewer feedback;
+ - a later reply in that same thread exists from the PR author or `@copilot` addressing the feedback.
+ - For each thread ID in `resolve_review_threads`, call:
+ ```bash
+ safeoutputs resolve_pull_request_review_thread --thread_id PRRT_kwDOABCD1234
+ ```
+ - If resolving one thread fails, record the failure and continue with remaining thread IDs; do not fail the run solely because one resolution attempt failed.
+
+4. **Dismiss stale `github-actions[bot]` blocking reviews when all PR review threads are resolved**
- **Slash-command guard**: If triggered via the `/souschef` slash command (`pull_request_comment` event), skip this dismissal step entirely — slash-command runs are acknowledgment nudges and must not perform automated review cleanup.
- - For `schedule` and `workflow_dispatch` runs, use the `dismiss_reviews` list returned by the `pr-processor` sub-agent. The sub-agent populates this list only when ALL review threads on the PR are resolved; leave reviews untouched if any thread remains unresolved.
+ - For `schedule` and `workflow_dispatch` runs, use the `dismiss_reviews` list returned by the `pr-processor` sub-agent. The sub-agent populates this list only when ALL review threads on the PR are resolved (including threads resolved in step 3); leave reviews untouched if any thread remains unresolved.
- `dismiss_pull_request_review` uses the `GITHUB_TOKEN`, which is always authenticated as `github-actions[bot]` regardless of the workflow trigger. It can therefore dismiss `github-actions[bot]`-authored reviews on any non-slash-command run.
- For each review ID in `dismiss_reviews`, call the native safe-output tool:
```bash
@@ -370,6 +390,7 @@ Then include the run counts as a compact table:
| branch_update_attempts | N |
| formatter_pushes | N |
| merge_main_scheduled | N |
+| resolved_review_threads | N |
| dismissed_reviews | N |
If any PRs were nudged, include a collapsible list of their numbers and titles.
@@ -380,7 +401,7 @@ Example (`create_issue` shell call):
safeoutputs create_issue --title "Run report — 2 nudged, 1 skipped" --body $'\n> ⚠️ **This is an automated status report. Do not assign this issue to a Copilot agent.**\n\n...'
```
-If `create_issue` is unavailable, fall back to `noop` with a condensed message containing the run counts, e.g. `"processed=4; skipped_checks_running=0; skipped_last_comment_from_sous_chef=1; skipped_cooldown=1; nudged=2; branch_update_attempts=0; formatter_pushes=0; merge_main_scheduled=1; dismissed_reviews=1"`.
+If `create_issue` is unavailable, fall back to `noop` with a condensed message containing the run counts, e.g. `"processed=4; skipped_checks_running=0; skipped_last_comment_from_sous_chef=1; skipped_cooldown=1; nudged=2; branch_update_attempts=0; formatter_pushes=0; merge_main_scheduled=1; resolved_review_threads=3; dismissed_reviews=1"`.
## Formatting Requirements
@@ -413,6 +434,7 @@ Given one PR number and compact metadata:
- a single combined nudge comment body:
- if `conflicting` is true: a targeted nudge asking `@copilot` to run `make merge-main` to resolve conflicts
- otherwise: a combined nudge covering unresolved review feedback, branch refresh, and any other forward-progress action including a direct instruction to run the `pr-finisher` skill — one comment only, never two; if unresolved PR reviews exist, include an explicit unresolved-reviews list (reviewer + direct link per unresolved review thread)
+ - `resolve_review_threads`: an array of unresolved PR review thread node IDs to resolve via safe output; include a thread only when the thread already contains a follow-up response from the PR author or `@copilot` that addresses the feedback
- `dismiss_reviews`: an array of review IDs — include a review ID only when the review was authored by `github-actions[bot]` with `CHANGES_REQUESTED` state AND all review threads on the PR are resolved (no unresolved threads remain); return an empty array if there are unresolved threads or no qualifying reviews
4. Make at most 8 tool calls total. If 8 calls are insufficient to reach a confident decision, set all fields to `null` and set `skip_reason: "insufficient_context"`.
5. Keep output compact JSON only — a single object, no prose.
diff --git a/pkg/cli/pr_sous_chef_workflow_contract_test.go b/pkg/cli/pr_sous_chef_workflow_contract_test.go
index f59b0d03053..2e4adc49ce2 100644
--- a/pkg/cli/pr_sous_chef_workflow_contract_test.go
+++ b/pkg/cli/pr_sous_chef_workflow_contract_test.go
@@ -27,7 +27,9 @@ func TestPRSousChefWorkflowAddCommentTargetContract(t *testing.T) {
assert.Contains(t, text, "Never emit `add_comment` without a numeric target field", "Workflow must forbid targetless add_comment items")
assert.Contains(t, text, "pr_number 12345", "Workflow should include a concrete add_comment pr_number example")
assert.Contains(t, text, "include an explicit unresolved-reviews list", "Workflow should require explicit unresolved review listing in nudge comments")
- assert.Contains(t, text, "Process all eligible PRs per run.", "Workflow should require processing all eligible PRs")
+ assert.Contains(t, text, "Process at most 4 nudges per run.", "Workflow should cap nudges per run")
+ assert.Contains(t, text, "Prioritize which PRs to nudge, in this order:", "Workflow should define deterministic PR prioritization for nudges")
+ assert.Contains(t, text, "stop creating new nudge comments once 4 PRs have been nudged", "Workflow should enforce a hard per-run nudge limit")
assert.Contains(t, text, "Make at most 8 tool calls total.", "Sub-agent should have a hard tool-call budget")
assert.Contains(t, text, "model: sonnet", "Sub-agent should use a Sonnet model alias")
assert.Contains(t, text, "skip_reason: \"sub_agent_error\"", "Workflow should skip failed sub-agent responses without retry")
@@ -35,6 +37,9 @@ func TestPRSousChefWorkflowAddCommentTargetContract(t *testing.T) {
assert.Contains(t, text, ".prs | length", "eligible_count should reflect the number of eligible PRs")
assert.Contains(t, text, "dismiss-pull-request-review", "Workflow should configure the native safe-output path for dismissing stale github-actions reviews")
assert.Contains(t, text, "safeoutputs dismiss_pull_request_review", "Workflow should call the native dismiss_pull_request_review safe-output tool")
+ assert.Contains(t, text, "resolve-pull-request-review-thread", "Workflow should configure native safe-output support for resolving review threads")
+ assert.Contains(t, text, "safeoutputs resolve_pull_request_review_thread", "Workflow should call the native resolve_pull_request_review_thread safe-output tool")
+ assert.Contains(t, text, "resolve_review_threads", "Workflow should track and process resolvable review threads")
assert.Contains(t, text, "all review threads on the PR are resolved", "Workflow must dismiss reviews only when all PR review threads are resolved")
assert.Contains(t, text, "slash-command runs are acknowledgment nudges and must not perform automated review cleanup", "Workflow must require slash-command runs to skip dismissal")
assert.Contains(t, text, "dismissed_reviews", "Noop summary must include dismissed_reviews counter")
From 69e67526e0c0d5bacbf7a91e6082e923a240d96c Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Fri, 10 Jul 2026 17:13:06 +0000
Subject: [PATCH 2/2] Refine pr sous-chef prioritization and review-thread
failure tracking
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
.github/workflows/pr-sous-chef.lock.yml | 2 +-
.github/workflows/pr-sous-chef.md | 4 ++--
pkg/cli/pr_sous_chef_workflow_contract_test.go | 2 ++
3 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/.github/workflows/pr-sous-chef.lock.yml b/.github/workflows/pr-sous-chef.lock.yml
index a82bdfde48e..94cdde70334 100644
--- a/.github/workflows/pr-sous-chef.lock.yml
+++ b/.github/workflows/pr-sous-chef.lock.yml
@@ -1,4 +1,4 @@
-# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"9cd58a3cfd50f2fff17e4ecfa36f3eb1a796c466578fdaf17d1b5974b2ff83b9","body_hash":"fc1357ab0fb8f68b718d5a4a93f046ee1c918ee64aa64cd84cd523d91ce12f89","strict":true,"agent_id":"pi","agent_model":"copilot/gpt-5.4","engine_versions":{"pi":"0.80.3"}}
+# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"9cd58a3cfd50f2fff17e4ecfa36f3eb1a796c466578fdaf17d1b5974b2ff83b9","body_hash":"5435e9fb02ce343b3a0921b33e17ff5ffc04220cff10c62eb543aa2057d24ace","strict":true,"agent_id":"pi","agent_model":"copilot/gpt-5.4","engine_versions":{"pi":"0.80.3"}}
# gh-aw-manifest: {"version":1,"secrets":["AWI_MAINTENANCE_TOKEN","COPILOT_GITHUB_TOKEN","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GH_AW_OTEL_GRAFANA_AUTHORIZATION","GH_AW_OTEL_GRAFANA_ENDPOINT","GH_AW_OTEL_SENTRY_AUTHORIZATION","GH_AW_OTEL_SENTRY_ENDPOINT","GITHUB_TOKEN"],"actions":[{"repo":"actions/cache/restore","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/cache/save","sha":"55cc8345863c7cc4c66a329aec7e433d2d1c52a9","version":"v6.1.0"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-go","sha":"924ae3a1cded613372ab5595356fb5720e22ba16","version":"v6.5.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.29","digest":"sha256:debc0b18ef8ea3a64585c4d1eea1099f0d9fa76b53d34a1f3c53b3225fe158fe","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.29@sha256:debc0b18ef8ea3a64585c4d1eea1099f0d9fa76b53d34a1f3c53b3225fe158fe"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.29","digest":"sha256:c7754df3f06f346c817db0525ba523cbdaf5349239fd7f37897c4250a8fc7bde","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.29@sha256:c7754df3f06f346c817db0525ba523cbdaf5349239fd7f37897c4250a8fc7bde"},{"image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.29","digest":"sha256:bfc90b1f10d2ff61dbbbf0d57600001f85bf5f6444ed78bc05d9f6677327e4b8","pinned_image":"ghcr.io/github/gh-aw-firewall/cli-proxy:0.27.29@sha256:bfc90b1f10d2ff61dbbbf0d57600001f85bf5f6444ed78bc05d9f6677327e4b8"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.29","digest":"sha256:7bfa0742f9a5bd6309507caaa80a8b6cf3e05bd95a1429affbf64cc94cfbd34f","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.29@sha256:7bfa0742f9a5bd6309507caaa80a8b6cf3e05bd95a1429affbf64cc94cfbd34f"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.5.0","digest":"sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4","pinned_image":"ghcr.io/github/github-mcp-server:v1.5.0@sha256:e25564dccc9110a70a77b9df560cbde11aa392fcb5f08b9abe5c4ebc6d146ea4"}]}
# This file was automatically generated by gh-aw. DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md
#
diff --git a/.github/workflows/pr-sous-chef.md b/.github/workflows/pr-sous-chef.md
index 7a281e86dd9..1769f1c5661 100644
--- a/.github/workflows/pr-sous-chef.md
+++ b/.github/workflows/pr-sous-chef.md
@@ -273,7 +273,7 @@ When this workflow is triggered by the `/souschef` slash command on a PR comment
- `mergeStateStatus == "CONFLICTING"` first (explicit merge-conflict unblock request).
- PRs with unresolved review threads where at least one thread already has a follow-up response from the PR author or `@copilot` but remains unresolved.
- Remaining PRs by most-recent `updatedAt`.
- If two PRs are still tied, prioritize the lower PR number first for deterministic behavior.
+ If two PRs are still tied, prioritize the lower PR number first for deterministic behavior and stable reruns.
6. After applying skip rules, stop creating new nudge comments once 4 PRs have been nudged in the current run. Continue processing only for required bookkeeping/reporting.
7. Use the `pr-processor` sub-agent for each PR; pass only the PR number and compact context.
8. If a `pr-processor` call returns non-JSON or an error, record `{pr_number: , skip_reason: "sub_agent_error"}` in the `skipped` array of the run-summary issue payload and move to the next PR without retrying.
@@ -355,7 +355,7 @@ For each PR that is not skipped:
```bash
safeoutputs resolve_pull_request_review_thread --thread_id PRRT_kwDOABCD1234
```
- - If resolving one thread fails, record the failure and continue with remaining thread IDs; do not fail the run solely because one resolution attempt failed.
+ - If resolving one thread fails, append `{pr_number: , skip_reason: "resolve_review_thread_failed", thread_id: ""}` to the run-summary `skipped` array and continue with remaining thread IDs; do not fail the run solely because one resolution attempt failed.
4. **Dismiss stale `github-actions[bot]` blocking reviews when all PR review threads are resolved**
- **Slash-command guard**: If triggered via the `/souschef` slash command (`pull_request_comment` event), skip this dismissal step entirely — slash-command runs are acknowledgment nudges and must not perform automated review cleanup.
diff --git a/pkg/cli/pr_sous_chef_workflow_contract_test.go b/pkg/cli/pr_sous_chef_workflow_contract_test.go
index 2e4adc49ce2..03f981fdae6 100644
--- a/pkg/cli/pr_sous_chef_workflow_contract_test.go
+++ b/pkg/cli/pr_sous_chef_workflow_contract_test.go
@@ -28,6 +28,7 @@ func TestPRSousChefWorkflowAddCommentTargetContract(t *testing.T) {
assert.Contains(t, text, "pr_number 12345", "Workflow should include a concrete add_comment pr_number example")
assert.Contains(t, text, "include an explicit unresolved-reviews list", "Workflow should require explicit unresolved review listing in nudge comments")
assert.Contains(t, text, "Process at most 4 nudges per run.", "Workflow should cap nudges per run")
+ assert.Contains(t, text, "add-comment:\n max: 4", "Workflow should hard-cap add_comment safe-output calls to 4 per run")
assert.Contains(t, text, "Prioritize which PRs to nudge, in this order:", "Workflow should define deterministic PR prioritization for nudges")
assert.Contains(t, text, "stop creating new nudge comments once 4 PRs have been nudged", "Workflow should enforce a hard per-run nudge limit")
assert.Contains(t, text, "Make at most 8 tool calls total.", "Sub-agent should have a hard tool-call budget")
@@ -40,6 +41,7 @@ func TestPRSousChefWorkflowAddCommentTargetContract(t *testing.T) {
assert.Contains(t, text, "resolve-pull-request-review-thread", "Workflow should configure native safe-output support for resolving review threads")
assert.Contains(t, text, "safeoutputs resolve_pull_request_review_thread", "Workflow should call the native resolve_pull_request_review_thread safe-output tool")
assert.Contains(t, text, "resolve_review_threads", "Workflow should track and process resolvable review threads")
+ assert.Contains(t, text, "skip_reason: \"resolve_review_thread_failed\"", "Workflow should explicitly record failed review-thread resolution attempts")
assert.Contains(t, text, "all review threads on the PR are resolved", "Workflow must dismiss reviews only when all PR review threads are resolved")
assert.Contains(t, text, "slash-command runs are acknowledgment nudges and must not perform automated review cleanup", "Workflow must require slash-command runs to skip dismissal")
assert.Contains(t, text, "dismissed_reviews", "Noop summary must include dismissed_reviews counter")