From 627425f37846f14cd96d751612481acf0809544a Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 14:42:28 -0500 Subject: [PATCH 01/12] ci-fix: mark validated draft PRs ready when the fixed test goes green MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a target-test verification + mark-ready gate (Step 3.6) to both ci-fix twins. When a [ci-fix]/[ci-fix-net11] draft PR reaches the green-surface or unrelated-flake branch, the loop now drills the PR's OWN AzDO test-results for the SPECIFIC test(s) the fix targeted. If every target test is Passed on >=1 leg and Failed on none (VALIDATED-GREEN), it: - posts a "target test validated green on " comment, and - transitions the draft PR to ready-for-review. This is a state transition only — it never approves and never merges; a human still reviews and merges. Overall red on UNRELATED legs no longer keeps a validated fix parked as a draft. Implementation: - New safe-output mark-pull-request-as-ready-for-review (max:3, target:"*", required-title-prefix + required-labels; both survive v0.80.9 compile, unlike update-pull-request). Defense-in-depth scoping to this workflow's own PRs. - New Step 3.6 with preconditions (isDraft, own-PR self-check, reached from green/unrelated-flake not caused-by-fix), T1 target-test identification, T2 AzDO test-results drill-down (not-executed => skip, honest no-overclaim), T3 idempotent per-head-SHA marker + dry-run gate. - Header description, outcome table, green/flake hooks, and summary tally updated; recompiled both locks (0/0, no action/version drift). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 57 ++++++--- .github/workflows/ci-status-fix-net11.md | 110 ++++++++++++++++-- .github/workflows/ci-status-fix.lock.yml | 57 ++++++--- .github/workflows/ci-status-fix.md | 110 ++++++++++++++++-- 4 files changed, 284 insertions(+), 50 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 078d77556633..6c40072a3793 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"4e931251d6d7cdf5f8a2a09cf7bd8d897d371641512affe8a5e06c4b616cec32","body_hash":"67a44401be38f48687acf99af90d029d3b986623fecbe9e9c56afa6e539f6646","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0506d309b131c4784d554cf9f57f5e22f79aad5683fc8496493159b438eb5079","body_hash":"16d71229b12f8b4c92e0f8b9ae3cd626081f5d2397615f15bff9c01dddb0b7c0","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -37,7 +37,9 @@ # humans (the open tracking issue is the hand-off surface; a dedicated # [ci-fix-net11][needs-human] PR is planned but currently deferred — see Step 6). CI on # the PR is kicked by a human `/azp run` for now; the loop watches, classifies, -# and re-fixes autonomously between kicks. +# and re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is +# confirmed green in that PR's own CI, the loop marks the draft PR ready for review +# (a state transition only — it never approves or merges). # Never mutes tests, but # de-flakes genuinely flaky ones (deterministic synchronization, no retries / # timeout bumps). Always skips visual-regression / screenshot issues. @@ -273,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_263a229552e96d78_EOF' + cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' - GH_AW_PROMPT_263a229552e96d78_EOF + GH_AW_PROMPT_b6fb3c86775391af_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_263a229552e96d78_EOF' + cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_263a229552e96d78_EOF + Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_b6fb3c86775391af_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_263a229552e96d78_EOF' + cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' - GH_AW_PROMPT_263a229552e96d78_EOF + GH_AW_PROMPT_b6fb3c86775391af_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_263a229552e96d78_EOF' + cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -332,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_263a229552e96d78_EOF + GH_AW_PROMPT_b6fb3c86775391af_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_263a229552e96d78_EOF' + cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' {{#runtime-import .github/workflows/ci-status-fix-net11.md}} - GH_AW_PROMPT_263a229552e96d78_EOF + GH_AW_PROMPT_b6fb3c86775391af_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -560,9 +562,9 @@ 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_b03b2af4be5b971b_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_b03b2af4be5b971b_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_d98051e1082451f2_EOF' + {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_d98051e1082451f2_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -570,6 +572,7 @@ jobs: "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix-net11] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", + "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", "push_to_pull_request_branch": " CONSTRAINTS: Maximum 3 push(es) can be made. The target pull request title must start with \"[ci-fix-net11] \".", "update_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be updated. Target: *." }, @@ -641,6 +644,24 @@ jobs: } } }, + "mark_pull_request_as_ready_for_review": { + "defaultMax": 1, + "fields": { + "pull_request_number": { + "issueOrPRNumber": true + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, "missing_data": { "defaultMax": 20, "fields": { @@ -1500,7 +1521,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: WORKFLOW_NAME: "CI Failure Fixer (net11.0)" - WORKFLOW_DESCRIPTION: "Periodic pass over open ci-scan-net11 tracking issues filed by the net11.0 CI\nfailure scanner (.github/workflows/ci-status-net11.md). This workflow targets\nthe `net11.0` branch EXCLUSIVELY: it processes only issues labelled ci-scan-net11 and\nopens every PR against net11.0. (The main branch is handled by the parallel\n.github/workflows/ci-status-fix.md — the two are split because gh-aw can\nonly transport a fix relative to ONE static base branch per workflow, and the\nmain↔net11.0 divergence exceeds gh-aw's 10 MB transport-patch cap.) The fixer\nopens ONE draft [ci-fix-net11] PR per actionable issue against net11.0, then WATCHES\nthat PR's own CI on later runs: when the fix's CI comes back red and the red is\ncaused by the fix itself, it pushes a fresh follow-up fix onto the SAME PR\nbranch (never a second PR) — up to 10 attempts — then stops and defers to\nhumans (the open tracking issue is the hand-off surface; a dedicated\n[ci-fix-net11][needs-human] PR is planned but currently deferred — see Step 6). CI on\nthe PR is kicked by a human `/azp run` for now; the loop watches, classifies,\nand re-fixes autonomously between kicks.\nNever mutes tests, but\nde-flakes genuinely flaky ones (deterministic synchronization, no retries /\ntimeout bumps). Always skips visual-regression / screenshot issues." + WORKFLOW_DESCRIPTION: "Periodic pass over open ci-scan-net11 tracking issues filed by the net11.0 CI\nfailure scanner (.github/workflows/ci-status-net11.md). This workflow targets\nthe `net11.0` branch EXCLUSIVELY: it processes only issues labelled ci-scan-net11 and\nopens every PR against net11.0. (The main branch is handled by the parallel\n.github/workflows/ci-status-fix.md — the two are split because gh-aw can\nonly transport a fix relative to ONE static base branch per workflow, and the\nmain↔net11.0 divergence exceeds gh-aw's 10 MB transport-patch cap.) The fixer\nopens ONE draft [ci-fix-net11] PR per actionable issue against net11.0, then WATCHES\nthat PR's own CI on later runs: when the fix's CI comes back red and the red is\ncaused by the fix itself, it pushes a fresh follow-up fix onto the SAME PR\nbranch (never a second PR) — up to 10 attempts — then stops and defers to\nhumans (the open tracking issue is the hand-off surface; a dedicated\n[ci-fix-net11][needs-human] PR is planned but currently deferred — see Step 6). CI on\nthe PR is kicked by a human `/azp run` for now; the loop watches, classifies,\nand re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is\nconfirmed green in that PR's own CI, the loop marks the draft PR ready for review\n(a state transition only — it never approves or merges).\nNever mutes tests, but\nde-flakes genuinely flaky ones (deterministic synchronization, no retries /\ntimeout bumps). Always skips visual-regression / screenshot issues." HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | @@ -1923,7 +1944,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index c404f39f525b..36d544f06ff7 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -15,7 +15,9 @@ description: | humans (the open tracking issue is the hand-off surface; a dedicated [ci-fix-net11][needs-human] PR is planned but currently deferred — see Step 6). CI on the PR is kicked by a human `/azp run` for now; the loop watches, classifies, - and re-fixes autonomously between kicks. + and re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is + confirmed green in that PR's own CI, the loop marks the draft PR ready for review + (a state transition only — it never approves or merges). Never mutes tests, but de-flakes genuinely flaky ones (deterministic synchronization, no retries / timeout bumps). Always skips visual-regression / screenshot issues. @@ -278,6 +280,24 @@ safe-outputs: # min-integrity:approved; the residual is body-marker edits only (no code, no # merge, no close), capped at max:3. Revisit required-* if a future gh-aw # compiler emits them for this output. + mark-pull-request-as-ready-for-review: + # Flip a validated draft [ci-fix-net11] PR to ready-for-review once the SPECIFIC + # test this PR was opened to fix is confirmed green in the PR's OWN CI (Step 3.6) — + # even when unrelated legs are red. The workflow is schedule/dispatch-triggered + # (no triggering-PR context), so target "*" lets the agent name the PR number it + # validated. This is a state transition ONLY: it never approves and never merges — + # a human still reviews and merges. + # PER-RUN total (not per-PR): a sweep may validate several PRs' target tests green. + max: 3 + target: "*" + # Hard constraint (defense-in-depth): only ever un-draft THIS workflow's own + # ci-fix PRs — [ci-fix-net11] title prefix AND agentic-workflows label — so a + # confused or prompt-injected agent cannot mark an arbitrary PR ready. (If the + # v0.80.9 compiler silently drops these — as documented for update-pull-request + # above — the Step 3.6 preconditions + min-integrity:approved are the compensating + # scope controls; verify against the lock after compiling.) + required-title-prefix: "[ci-fix-net11] " + required-labels: [agentic-workflows] timeout-minutes: 90 @@ -419,8 +439,9 @@ For every open tracking issue in scope, converge on exactly one outcome: | Open first help-wanted draft `[ci-fix-net11]` PR | No open PR yet; a plausible candidate exists but cannot be runner-validated (device/UI tests) (attempt 1) | | Open first de-flake draft `[ci-fix-net11]` PR | No open PR yet; failure is intermittent (green-on-retry) from a genuine test-quality defect; a deterministic-synchronization fix is producible (attempt 1, Step 4.7 bucket b) | | Advance an existing PR (push attempt N+1) | Open PR's own CI settled red *because of the fix itself*, no human engaged, marker < 10 — push a NEW distinct fix onto the same branch (Step 3.5 → 5.6) | -| Surface a validated-green PR | Open PR's own CI settled green — comment "validated, attempt N/10; ready for review" and do NOT advance (Step 3.5) | -| Annotate an unrelated-flake red | Open PR is red only on baseline-flake / unrelated legs — comment which leg needs a re-run; do NOT burn an attempt (Step 3.5) | +| Surface a validated-green PR | Open PR's own CI settled green — comment "validated, attempt N/10; ready for review" and do NOT advance (Step 3.5), then mark the draft PR ready for review once the fixed test is confirmed green (Step 3.6) | +| Annotate an unrelated-flake red | Open PR is red only on baseline-flake / unrelated legs — comment which leg needs a re-run; do NOT burn an attempt (Step 3.5); if the SPECIFIC fixed test is confirmed green on that build, still mark the draft PR ready for review (Step 3.6) | +| Mark a validated PR ready for review | The specific test this PR fixed is confirmed green in the PR's own CI (even if unrelated legs are red) — comment the target-test result and transition the draft PR to ready for review; never approve or merge (Step 3.6) | | Wait | Open PR's CI is pending / not yet settled on the current head SHA — do nothing this cycle (Step 3.5) | | Hand-off skip (attempt cap) | Marker == 10 and the signature still reproduces — stop and defer to humans; the dedicated `[ci-fix-net11][needs-human]` PR is planned but currently deferred (Step 6) | | Recorded skip | Visual-regression, human engaged, already-handled, fixed-in-latest-build, infra-flake, out-of-bounds, only-mute-available, or no novel approach producible | @@ -724,7 +745,8 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: validated — the fix's CI is green on . Ready for human review.` Name any `/azp`-gated legs (uitests def 313 / devicetests def 314) that have not run and still need a maintainer `/azp run`. Do NOT advance. Record - `surfaced-green PR #

(attempt /10)` and stop. *(This directly + `surfaced-green PR #

(attempt /10)`, then run **Step 3.6** + (target-test readiness gate) for this PR before stopping. *(This directly attacks the real bottleneck — no reviews — so it is the highest-value outcome.)* 4. **Red → classify caused-by-fix vs unrelated-flake.** If `C.overallConclusion == "failure"`, analyze the PR's OWN failing build (NOT `net11.0`): find the AzDO @@ -743,7 +765,8 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: indeterminate. **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `♻️` unrelated-flake body to the run log, tally `dry-run: would-annotate-flake PR #

`, and stop. Otherwise `add_comment` on PR #

: `♻️ Attempt /10: red is unrelated flake on leg(s) () on ; the fix itself is not implicated. A maintainer re-run (/azp run ) should clear it.` Record - `annotated-flake PR #

(head )` and stop. *(Round 1: human re-runs; + `annotated-flake PR #

(head )`, then run **Step 3.6** + (target-test readiness gate) for this PR before stopping. *(Round 1: human re-runs; Round 2: auto re-trigger.)* - **Caused by the fix** (a failed leg still matches the original target signature, or the fix introduced a NEW failure): advance an attempt. @@ -762,6 +785,77 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: from every prior commit on this branch**, emitted via the Step 5.6 ADVANCE path (push onto the same PR). +#### Step 3.6 — Target-test verification & mark-ready gate + +Reached from the Step 3 **green-surface** branch and the Step 4 **unrelated-flake** +branch, AFTER that branch has posted its comment. Purpose: confirm the SPECIFIC +test(s) this PR was opened to fix now PASS in the PR's own CI, and — only when they do +— transition the draft `[ci-fix-net11]` PR to **ready for review** so a maintainer sees +a validated fix instead of a draft. This is the ONLY place the loop flips draft→ready; +it is a state transition, **never** an approval or a merge (a human still reviews and +merges). Overall red on *unrelated* legs must NOT gate readiness — we validate the fix, +not the base branch's flakiness. + +**Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

+()` and stop this gate): +- `C.isDraft == true` — if the PR is already ready, record `already-ready PR #

` and stop. +- The PR is unmistakably THIS workflow's own: `[ci-fix-net11] ` title prefix AND the + `agentic-workflows` label (mirrors the safe-output lock; the compensating scope + control if the v0.80.9 compiler drops the declarative required-*). +- You reached this gate from Step 3 (green) or Step 4 (**unrelated-flake**) — i.e. the + fix is NOT implicated in any red. If Step 4 classified the red as **caused by the + fix** (ADVANCE), do NOT run this gate — advance the attempt instead. + +**T1 — Identify the target test(s).** From the `[ci-scan-net11]` issue signature the fix +addresses (and the PR's own diff), extract the fully-qualified test method name(s) the +fix targets — e.g. `SafeAreaShouldWorkOnAllShellTabs`. For a de-flake it is the +de-flaked test; for a product fix it is the originally-failing test(s). If NO specific +test can be identified (e.g. a product build-break rather than a test failure), record +`skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix +is validated by overall-green alone, which the Step 3 branch already handles. + +**T2 — Drill into the PR's own build test-results.** Using the SAME build-discovery as +Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` or `sourceVersion == +C.headSha`), find the build(s) on `C.headSha` for the pipeline(s) that actually RUN the +target test — `maui-pr` (def 302) for unit/integration tests, `maui-pr-uitests` (def +313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device tests — then query +the AzDO test-results REST API on `dev.azure.com` for each target test's outcome on that +build: + +```bash +ORG=dnceng-public; PROJ=public; P=; BUILD= +# test runs for the build: +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ + | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' +# per run id, look for each target test's outcome (repeat per target test): +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ + | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' +``` + +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it appears with +`outcome == "Passed"` on at least one platform leg AND appears with `outcome == +"Failed"` on NO leg. A target test that never appears at all (**not executed** — e.g. an +`/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been kicked) is +NOT validated: record `skipped: target test not yet executed on PR #

+( not run — needs /azp run)` and stop this gate WITHOUT marking ready. Do NOT +overclaim — a green *sibling* leg in the same group is not the target test. + +**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: +- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` + comment for THIS head SHA already exists (or `C.isDraft` is already false), record + `already-marked-ready PR #

(head )` and stop. +- **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended + readiness comment and "would mark ready" to the run log, tally `dry-run: + would-mark-ready PR #

`, and stop. +- Otherwise emit BOTH safe-outputs for THIS PR number `

`: + 1. `add_comment`: `🎯 Target test validated green on + passed (, buildId ). — not caused by this fix."> Transitioning this PR + from draft to ready for review; a maintainer still reviews and merges.` + 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification + naming the validated test(s) and ``. +- Record `marked-ready PR #

(target green on )` and stop. + #### Step 3.5.R — Maintainer change-request response (Track C) Reached from Step 3.5 gate 0. Goal: when an **eligible human reviewer** (Hard-Rule @@ -1406,8 +1500,10 @@ Per issue, append one outcome line to `/tmp/gh-aw/agent/coverage.txt`: `advance-PR #

attempt /10` (ADVANCE mode — new commit pushed to the existing PR), `surfaced-green PR #

` (fix's own CI went green; commented for review, did not advance), `annotated-flake PR #

` (red was unrelated flake; -commented, attempt NOT burned), `waiting PR #

` (CI not settled yet), -`dry-run: would-`, `skipped: `. (The +commented, attempt NOT burned), `marked-ready PR #

` (the specific fixed test +was confirmed green in the PR's own CI; draft flipped to ready for review), +`waiting PR #

` (CI not settled yet), +`dry-run: would-`, `skipped: `. (The `needs-human-PR` outcome is reserved for the deferred hand-off — Step 6 currently records a skip instead, so it is not emitted.) diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 93dc5969cb0d..a04910f74993 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"f014161967589ebcaf1ac5ec6f3c88ee5a4388d28b55a07dc36c45b7b2aebab6","body_hash":"86c6b2d4c3df13da14c6a3c8b211381fcc9f97bb1951ff7b80588a2c5338e00c","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5d24a1cd488401c009ba5daff2dc242dcd7a6bd10ccebbea660d48d8efd8af53","body_hash":"f0ad185861452d572741ea74303af7591f4534a56ad2d12a7baa68f2427b0402","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -37,7 +37,9 @@ # humans (the open tracking issue is the hand-off surface; a dedicated # [ci-fix][needs-human] PR is planned but currently deferred — see Step 6). CI on # the PR is kicked by a human `/azp run` for now; the loop watches, classifies, -# and re-fixes autonomously between kicks. +# and re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is +# confirmed green in that PR's own CI, the loop marks the draft PR ready for review +# (a state transition only — it never approves or merges). # Never mutes tests, but # de-flakes genuinely flaky ones (deterministic synchronization, no retries / # timeout bumps). Always skips visual-regression / screenshot issues. @@ -273,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_25cf75111b670167_EOF' + cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' - GH_AW_PROMPT_25cf75111b670167_EOF + GH_AW_PROMPT_25e949294484c30e_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_25cf75111b670167_EOF' + cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_25cf75111b670167_EOF + Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_25e949294484c30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_25cf75111b670167_EOF' + cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' - GH_AW_PROMPT_25cf75111b670167_EOF + GH_AW_PROMPT_25e949294484c30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_25cf75111b670167_EOF' + cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -332,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_25cf75111b670167_EOF + GH_AW_PROMPT_25e949294484c30e_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_25cf75111b670167_EOF' + cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' {{#runtime-import .github/workflows/ci-status-fix.md}} - GH_AW_PROMPT_25cf75111b670167_EOF + GH_AW_PROMPT_25e949294484c30e_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -554,9 +556,9 @@ 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_fa2a69fad5fd0485_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_fa2a69fad5fd0485_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_6c81318c84474248_EOF' + {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_6c81318c84474248_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | @@ -564,6 +566,7 @@ jobs: "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", + "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", "push_to_pull_request_branch": " CONSTRAINTS: Maximum 3 push(es) can be made. The target pull request title must start with \"[ci-fix] \".", "update_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be updated. Target: *." }, @@ -635,6 +638,24 @@ jobs: } } }, + "mark_pull_request_as_ready_for_review": { + "defaultMax": 1, + "fields": { + "pull_request_number": { + "issueOrPRNumber": true + }, + "reason": { + "required": true, + "type": "string", + "sanitize": true, + "maxLength": 65000 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, "missing_data": { "defaultMax": 20, "fields": { @@ -1494,7 +1515,7 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: WORKFLOW_NAME: "CI Failure Fixer (main)" - WORKFLOW_DESCRIPTION: "Periodic pass over open ci-scan tracking issues filed by the main-branch CI\nfailure scanner (.github/workflows/ci-status-main.md). This workflow targets\nthe `main` branch EXCLUSIVELY: it processes only issues labelled ci-scan and\nopens every PR against main. (The net11.0 branch is handled by the parallel\n.github/workflows/ci-status-fix-net11.md — the two are split because gh-aw can\nonly transport a fix relative to ONE static base branch per workflow, and the\nmain↔net11.0 divergence exceeds gh-aw's 10 MB transport-patch cap.) The fixer\nopens ONE draft [ci-fix] PR per actionable issue against main, then WATCHES\nthat PR's own CI on later runs: when the fix's CI comes back red and the red is\ncaused by the fix itself, it pushes a fresh follow-up fix onto the SAME PR\nbranch (never a second PR) — up to 10 attempts — then stops and defers to\nhumans (the open tracking issue is the hand-off surface; a dedicated\n[ci-fix][needs-human] PR is planned but currently deferred — see Step 6). CI on\nthe PR is kicked by a human `/azp run` for now; the loop watches, classifies,\nand re-fixes autonomously between kicks.\nNever mutes tests, but\nde-flakes genuinely flaky ones (deterministic synchronization, no retries /\ntimeout bumps). Always skips visual-regression / screenshot issues." + WORKFLOW_DESCRIPTION: "Periodic pass over open ci-scan tracking issues filed by the main-branch CI\nfailure scanner (.github/workflows/ci-status-main.md). This workflow targets\nthe `main` branch EXCLUSIVELY: it processes only issues labelled ci-scan and\nopens every PR against main. (The net11.0 branch is handled by the parallel\n.github/workflows/ci-status-fix-net11.md — the two are split because gh-aw can\nonly transport a fix relative to ONE static base branch per workflow, and the\nmain↔net11.0 divergence exceeds gh-aw's 10 MB transport-patch cap.) The fixer\nopens ONE draft [ci-fix] PR per actionable issue against main, then WATCHES\nthat PR's own CI on later runs: when the fix's CI comes back red and the red is\ncaused by the fix itself, it pushes a fresh follow-up fix onto the SAME PR\nbranch (never a second PR) — up to 10 attempts — then stops and defers to\nhumans (the open tracking issue is the hand-off surface; a dedicated\n[ci-fix][needs-human] PR is planned but currently deferred — see Step 6). CI on\nthe PR is kicked by a human `/azp run` for now; the loop watches, classifies,\nand re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is\nconfirmed green in that PR's own CI, the loop marks the draft PR ready for review\n(a state transition only — it never approves or merges).\nNever mutes tests, but\nde-flakes genuinely flaky ones (deterministic synchronization, no retries /\ntimeout bumps). Always skips visual-regression / screenshot issues." HAS_PATCH: ${{ needs.agent.outputs.has_patch }} with: script: | @@ -1910,7 +1931,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index d3227e25170c..0eafaa7b7161 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -15,7 +15,9 @@ description: | humans (the open tracking issue is the hand-off surface; a dedicated [ci-fix][needs-human] PR is planned but currently deferred — see Step 6). CI on the PR is kicked by a human `/azp run` for now; the loop watches, classifies, - and re-fixes autonomously between kicks. + and re-fixes autonomously between kicks. When the SPECIFIC test a PR fixed is + confirmed green in that PR's own CI, the loop marks the draft PR ready for review + (a state transition only — it never approves or merges). Never mutes tests, but de-flakes genuinely flaky ones (deterministic synchronization, no retries / timeout bumps). Always skips visual-regression / screenshot issues. @@ -268,6 +270,24 @@ safe-outputs: # min-integrity:approved; the residual is body-marker edits only (no code, no # merge, no close), capped at max:3. Revisit required-* if a future gh-aw # compiler emits them for this output. + mark-pull-request-as-ready-for-review: + # Flip a validated draft [ci-fix] PR to ready-for-review once the SPECIFIC test + # this PR was opened to fix is confirmed green in the PR's OWN CI (Step 3.6) — + # even when unrelated legs are red. The workflow is schedule/dispatch-triggered + # (no triggering-PR context), so target "*" lets the agent name the PR number it + # validated. This is a state transition ONLY: it never approves and never merges — + # a human still reviews and merges. + # PER-RUN total (not per-PR): a sweep may validate several PRs' target tests green. + max: 3 + target: "*" + # Hard constraint (defense-in-depth): only ever un-draft THIS workflow's own + # ci-fix PRs — [ci-fix] title prefix AND agentic-workflows label — so a confused + # or prompt-injected agent cannot mark an arbitrary PR ready. (If the v0.80.9 + # compiler silently drops these — as documented for update-pull-request above — + # the Step 3.6 preconditions + min-integrity:approved are the compensating scope + # controls; verify against the lock after compiling.) + required-title-prefix: "[ci-fix] " + required-labels: [agentic-workflows] timeout-minutes: 90 @@ -409,8 +429,9 @@ For every open tracking issue in scope, converge on exactly one outcome: | Open first help-wanted draft `[ci-fix]` PR | No open PR yet; a plausible candidate exists but cannot be runner-validated (device/UI tests) (attempt 1) | | Open first de-flake draft `[ci-fix]` PR | No open PR yet; failure is intermittent (green-on-retry) from a genuine test-quality defect; a deterministic-synchronization fix is producible (attempt 1, Step 4.7 bucket b) | | Advance an existing PR (push attempt N+1) | Open PR's own CI settled red *because of the fix itself*, no human engaged, marker < 10 — push a NEW distinct fix onto the same branch (Step 3.5 → 5.6) | -| Surface a validated-green PR | Open PR's own CI settled green — comment "validated, attempt N/10; ready for review" and do NOT advance (Step 3.5) | -| Annotate an unrelated-flake red | Open PR is red only on baseline-flake / unrelated legs — comment which leg needs a re-run; do NOT burn an attempt (Step 3.5) | +| Surface a validated-green PR | Open PR's own CI settled green — comment "validated, attempt N/10; ready for review" and do NOT advance (Step 3.5), then mark the draft PR ready for review once the fixed test is confirmed green (Step 3.6) | +| Annotate an unrelated-flake red | Open PR is red only on baseline-flake / unrelated legs — comment which leg needs a re-run; do NOT burn an attempt (Step 3.5); if the SPECIFIC fixed test is confirmed green on that build, still mark the draft PR ready for review (Step 3.6) | +| Mark a validated PR ready for review | The specific test this PR fixed is confirmed green in the PR's own CI (even if unrelated legs are red) — comment the target-test result and transition the draft PR to ready for review; never approve or merge (Step 3.6) | | Wait | Open PR's CI is pending / not yet settled on the current head SHA — do nothing this cycle (Step 3.5) | | Hand-off skip (attempt cap) | Marker == 10 and the signature still reproduces — stop and defer to humans; the dedicated `[ci-fix][needs-human]` PR is planned but currently deferred (Step 6) | | Recorded skip | Visual-regression, human engaged, already-handled, fixed-in-latest-build, infra-flake, out-of-bounds, only-mute-available, or no novel approach producible | @@ -714,7 +735,8 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: — the fix's CI is green on . Ready for human review.` Name any `/azp`-gated legs (uitests def 313 / devicetests def 314) that have not run and still need a maintainer `/azp run`. Do NOT advance. Record - `surfaced-green PR #

(attempt /10)` and stop. *(This directly + `surfaced-green PR #

(attempt /10)`, then run **Step 3.6** + (target-test readiness gate) for this PR before stopping. *(This directly attacks the real bottleneck — no reviews — so it is the highest-value outcome.)* 4. **Red → classify caused-by-fix vs unrelated-flake.** If `C.overallConclusion == "failure"`, analyze the PR's OWN failing build (NOT `main`): find the AzDO @@ -733,7 +755,8 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: indeterminate. **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `♻️` unrelated-flake body to the run log, tally `dry-run: would-annotate-flake PR #

`, and stop. Otherwise `add_comment` on PR #

: `♻️ Attempt /10: red is unrelated flake on leg(s) () on ; the fix itself is not implicated. A maintainer re-run (/azp run ) should clear it.` Record - `annotated-flake PR #

(head )` and stop. *(Round 1: human re-runs; + `annotated-flake PR #

(head )`, then run **Step 3.6** + (target-test readiness gate) for this PR before stopping. *(Round 1: human re-runs; Round 2: auto re-trigger.)* - **Caused by the fix** (a failed leg still matches the original target signature, or the fix introduced a NEW failure): advance an attempt. @@ -752,6 +775,77 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: from every prior commit on this branch**, emitted via the Step 5.6 ADVANCE path (push onto the same PR). +#### Step 3.6 — Target-test verification & mark-ready gate + +Reached from the Step 3 **green-surface** branch and the Step 4 **unrelated-flake** +branch, AFTER that branch has posted its comment. Purpose: confirm the SPECIFIC +test(s) this PR was opened to fix now PASS in the PR's own CI, and — only when they do +— transition the draft `[ci-fix]` PR to **ready for review** so a maintainer sees a +validated fix instead of a draft. This is the ONLY place the loop flips draft→ready; it +is a state transition, **never** an approval or a merge (a human still reviews and +merges). Overall red on *unrelated* legs must NOT gate readiness — we validate the fix, +not the base branch's flakiness. + +**Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

+()` and stop this gate): +- `C.isDraft == true` — if the PR is already ready, record `already-ready PR #

` and stop. +- The PR is unmistakably THIS workflow's own: `[ci-fix] ` title prefix AND the + `agentic-workflows` label (mirrors the safe-output lock; the compensating scope + control if the v0.80.9 compiler drops the declarative required-*). +- You reached this gate from Step 3 (green) or Step 4 (**unrelated-flake**) — i.e. the + fix is NOT implicated in any red. If Step 4 classified the red as **caused by the + fix** (ADVANCE), do NOT run this gate — advance the attempt instead. + +**T1 — Identify the target test(s).** From the `[ci-scan]` issue signature the fix +addresses (and the PR's own diff), extract the fully-qualified test method name(s) the +fix targets — e.g. `SafeAreaShouldWorkOnAllShellTabs`. For a de-flake it is the +de-flaked test; for a product fix it is the originally-failing test(s). If NO specific +test can be identified (e.g. a product build-break rather than a test failure), record +`skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix +is validated by overall-green alone, which the Step 3 branch already handles. + +**T2 — Drill into the PR's own build test-results.** Using the SAME build-discovery as +Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` or `sourceVersion == +C.headSha`), find the build(s) on `C.headSha` for the pipeline(s) that actually RUN the +target test — `maui-pr` (def 302) for unit/integration tests, `maui-pr-uitests` (def +313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device tests — then query +the AzDO test-results REST API on `dev.azure.com` for each target test's outcome on that +build: + +```bash +ORG=dnceng-public; PROJ=public; P=; BUILD= +# test runs for the build: +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ + | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' +# per run id, look for each target test's outcome (repeat per target test): +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ + | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' +``` + +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it appears with +`outcome == "Passed"` on at least one platform leg AND appears with `outcome == +"Failed"` on NO leg. A target test that never appears at all (**not executed** — e.g. an +`/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been kicked) is +NOT validated: record `skipped: target test not yet executed on PR #

+( not run — needs /azp run)` and stop this gate WITHOUT marking ready. Do NOT +overclaim — a green *sibling* leg in the same group is not the target test. + +**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: +- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` + comment for THIS head SHA already exists (or `C.isDraft` is already false), record + `already-marked-ready PR #

(head )` and stop. +- **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended + readiness comment and "would mark ready" to the run log, tally `dry-run: + would-mark-ready PR #

`, and stop. +- Otherwise emit BOTH safe-outputs for THIS PR number `

`: + 1. `add_comment`: `🎯 Target test validated green on + passed (, buildId ). — not caused by this fix."> Transitioning this PR + from draft to ready for review; a maintainer still reviews and merges.` + 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification + naming the validated test(s) and ``. +- Record `marked-ready PR #

(target green on )` and stop. + #### Step 3.5.R — Maintainer change-request response (Track C) Reached from Step 3.5 gate 0. Goal: when an **eligible human reviewer** (Hard-Rule @@ -1394,8 +1488,10 @@ Per issue, append one outcome line to `/tmp/gh-aw/agent/coverage.txt`: `advance-PR #

attempt /10` (ADVANCE mode — new commit pushed to the existing PR), `surfaced-green PR #

` (fix's own CI went green; commented for review, did not advance), `annotated-flake PR #

` (red was unrelated flake; -commented, attempt NOT burned), `waiting PR #

` (CI not settled yet), -`dry-run: would-`, `skipped: `. (The +commented, attempt NOT burned), `marked-ready PR #

` (the specific fixed test +was confirmed green in the PR's own CI; draft flipped to ready for review), +`waiting PR #

` (CI not settled yet), +`dry-run: would-`, `skipped: `. (The `needs-human-PR` outcome is reserved for the deferred hand-off — Step 6 currently records a skip instead, so it is not emitted.) From e18cec28d4137d9ff43e81a6e209891fde7a61e6 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 15:02:10 -0500 Subject: [PATCH 02/12] ci-fix: don't treat the loop's own web-flow-committed create-PR commit as human engagement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gh-aw's create_pull_request builds a PR's initial commit through the GitHub API, which stamps author=github-actions[bot] but committer=web-flow. Since 2f6b77b330 removed web-flow from $BotLogins (to catch a maintainer 'Update branch'), Test-AnyHumanCommitActor's committer check began reading that self-authored commit as human engagement — so every freshly opened [ci-fix] draft PR looked 'human owned' from its first commit and the watch loop skipped it forever (never reaching the surface-green / mark-ready path). Fix: a human COMMITTER only trips the hand-off when the commit AUTHOR is not one of this workflow's own bot identities ($LoopBotCommitAuthors). A human AUTHOR still counts unconditionally, so maintainer direct commits and web-flow-authored 'Update branch' merges continue to hand off correctly. Unit-tested across all six author/committer shapes. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Query-CiFixPRs.ps1 | 42 +++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/.github/scripts/Query-CiFixPRs.ps1 b/.github/scripts/Query-CiFixPRs.ps1 index 822a26e114ea..93c38ba2381d 100755 --- a/.github/scripts/Query-CiFixPRs.ps1 +++ b/.github/scripts/Query-CiFixPRs.ps1 @@ -33,9 +33,17 @@ $BotLogins = @( # a maintainer who updates the branch via the web UI SHOULD trip the hand-off boundary # (Test-AnyHumanCommitActor inspects the committer, which is web-flow on those merges); # (2) attempt accounting — botCommitCount is author-based, so a web-flow-*authored* - # commit must NOT inflate the count toward the 10-cap. The workflow's own pushes are - # authored AND committed by github-actions[bot], never web-flow, so treating web-flow - # as human never masks a genuine bot attempt. + # commit must NOT inflate the count toward the 10-cap. + # + # CAVEAT (see Test-AnyHumanCommitActor + $LoopBotCommitAuthors): this workflow's OWN + # create_pull_request commit is authored by github-actions[bot] but COMMITTED by + # web-flow, because gh-aw builds the PR's initial commit through the GitHub API and + # GitHub stamps API-created commits with a web-flow committer. So a web-flow committer + # does NOT by itself prove human engagement — Test-AnyHumanCommitActor only lets a + # web-flow (or any human) committer trip the hand-off when the commit AUTHOR is not one + # of this workflow's own bot identities. push-to-pull-request-branch commits, by + # contrast, are authored AND committed by github-actions[bot] (a real git push), so the + # author check alone already excludes them. 'app/github-actions', 'dotnet-maestro[bot]', 'azure-pipelines[bot]', @@ -53,6 +61,19 @@ $BotLogins = @( 'maui-bot', 'maui-bot[bot]' ) + +# Commit-author logins that identify THIS workflow's own pushes. A commit authored by one +# of these is either the create_pull_request commit or a push-to-pull-request-branch commit +# — never a human action — even when GitHub stamps its COMMITTER as 'web-flow' (which it +# does for the API-created initial PR commit). Test-AnyHumanCommitActor uses this list to +# stop that self-authored commit's web-flow committer from being read as human engagement, +# which would otherwise make every freshly opened [ci-fix] PR look 'human owned' from its +# first commit and be skipped by the watch loop forever. Compared lowercased. +$LoopBotCommitAuthors = @( + 'github-actions[bot]', + 'github-actions', + 'app/github-actions' +) # NOTE: 'action_required' is deliberately EXCLUDED. That conclusion means a human # must act (an Actions approval gate, or an integration awaiting a manual run) — # it reports status=completed, so treating it as a failure would let a settled head @@ -205,7 +226,20 @@ function Test-AnyHumanCommitActor { $authorLogin = if ($commit.author -and $commit.author.login) { [string]$commit.author.login } else { $null } $committerLogin = if ($commit.committer -and $commit.committer.login) { [string]$commit.committer.login } else { $null } - if ((Test-IsHumanLogin -Login $authorLogin) -or (Test-IsHumanLogin -Login $committerLogin)) { + # A human AUTHOR always counts (a maintainer's direct commit; a web-flow-authored + # 'Update branch' merge lands here too because web-flow is treated as human). + if (Test-IsHumanLogin -Login $authorLogin) { + return $true + } + + # A human COMMITTER (e.g. 'web-flow' on a web-UI 'Update branch' merge) counts as + # human engagement ONLY when the author is not one of THIS workflow's own bot + # identities. gh-aw's create_pull_request builds the PR's initial commit through the + # GitHub API, which stamps author=github-actions[bot] but committer=web-flow; without + # this carve-out that self-authored commit reads as 'human engaged' and every fresh + # [ci-fix] PR is skipped by the watch loop from its very first commit. + $authorKey = if ($null -ne $authorLogin) { $authorLogin.Trim().ToLowerInvariant() } else { '' } + if ((Test-IsHumanLogin -Login $committerLogin) -and ($LoopBotCommitAuthors -notcontains $authorKey)) { return $true } } From b6a64b3b187a7b4282d8d6f9c740e4be3ee63b0f Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 16:13:41 -0500 Subject: [PATCH 03/12] =?UTF-8?q?ci-fix:=20gate=202=20target-focused=20fas?= =?UTF-8?q?t-path=20=E2=80=94=20mark=20draft=20PR=20ready=20as=20soon=20as?= =?UTF-8?q?=20the=20fixed=20test=20is=20green?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Gate 2 previously waited for the ENTIRE build to settle (checksSettled) before Step 3.6 could mark a validated draft [ci-fix] PR ready. That let unrelated *pending* legs (e.g. 20 unrelated macOS UITests legs) keep a fix parked as a draft for hours even though its own target test had already gone green. Add a target-focused fast-path (gate 2a): when a draft [ci-fix]/[ci-fix-net11] PR's SPECIFIC target test is VALIDATED-GREEN on the current head SHA (Passed on >=1 leg, Failed on none) AND every ALREADY-CONCLUDED red leg classifies as unrelated flake, mark ready now regardless of unrelated pending legs. The early-out never advances an attempt and never acts on a red that could be the fix's fault; caused-by-fix reds and un-run target legs still fall through to the existing WAIT (2b). Mirrored to both twins; locks recompiled (body_hash only, v0.80.9, no action drift). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 43 +++++++++++++------ .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 43 +++++++++++++------ 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 6c40072a3793..810f7dcad0a4 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0506d309b131c4784d554cf9f57f5e22f79aad5683fc8496493159b438eb5079","body_hash":"16d71229b12f8b4c92e0f8b9ae3cd626081f5d2397615f15bff9c01dddb0b7c0","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0506d309b131c4784d554cf9f57f5e22f79aad5683fc8496493159b438eb5079","body_hash":"34f301acea63c8adbb08b9b182be68dca7c8053342240d85d6499919b2f5c4f2","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 36d544f06ff7..f6530fcd78f8 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -716,14 +716,29 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: 1. **Human engaged.** If `C.humanEngaged` → `skipped: human engaged on PR #

; deferring` and stop. Never fight a human reviewer — the intentional hand-off boundary still holds the moment a person touches the PR. -2. **CI not settled / unknown / incomplete prefetch.** If `C.checksSettled == false` - OR `C.overallConclusion` is `pending`, `neutral`, or `unknown`, OR - `C.dataComplete == false` → the fix's CI has not finished on the current head SHA - (`C.headSha`), or the prefetch could not fully read this PR (a partial read can - understate `humanEngaged` / `attempt`). `skipped: PR #

CI pending / prefetch - incomplete on ; waiting` and stop. *(Round 1: this is where a - maintainer `/azp run` is awaited — the `/azp`-gated uitests/devicetests legs will - not have run until a human kicks them.)* +2. **CI not settled — but validate the target test first (target-focused readiness).** + If `C.checksSettled == false` OR `C.overallConclusion` is `pending`, `neutral`, or + `unknown`, OR `C.dataComplete == false` → the *overall* build has not finished on the + current head SHA (`C.headSha`), or the prefetch could not fully read this PR (a partial + read can understate `humanEngaged` / `attempt`). Unrelated legs still draining must NOT + keep an already-proven fix parked as a draft, so before waiting, try the target-focused + fast-path: + - **2a — Target-green fast-path (draft `[ci-fix-net11]` PRs only).** If `C.dataComplete + == true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix-net11] ` title prefix + AND the `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: + identify the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target + test is **VALIDATED-GREEN** (`Passed` on ≥1 leg, `Failed` on NO leg) AND every leg in + `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / + Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven + regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) + and stop. This early-out NEVER advances an attempt and NEVER acts on a red that could + be the fix's fault. + - **2b — Otherwise WAIT.** If the target test has not yet executed (pending/absent on + its leg), or a completed red is (or may be) caused by the fix, or `C.dataComplete == + false`, or this PR has no identifiable target test → `skipped: PR #

CI pending / + target not yet validated on ; waiting` and stop. *(Round 1: this is where a + maintainer `/azp run` is awaited — the `/azp`-gated uitests/devicetests legs will not + have run until a human kicks them.)* 3. **Green → surface for review.** If `C.overallConclusion == "success"`: the checks that RAN are green. **Primary-gate check first:** the deterministic `success` verdict only certifies "at least one green check, nothing failing or @@ -787,8 +802,9 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: #### Step 3.6 — Target-test verification & mark-ready gate -Reached from the Step 3 **green-surface** branch and the Step 4 **unrelated-flake** -branch, AFTER that branch has posted its comment. Purpose: confirm the SPECIFIC +Reached from the Step 3 **green-surface** branch, the Step 4 **unrelated-flake** branch +(AFTER that branch has posted its comment), and the Step 3.5 **gate-2 target-focused +fast-path** (2a — while unrelated legs are still pending). Purpose: confirm the SPECIFIC test(s) this PR was opened to fix now PASS in the PR's own CI, and — only when they do — transition the draft `[ci-fix-net11]` PR to **ready for review** so a maintainer sees a validated fix instead of a draft. This is the ONLY place the loop flips draft→ready; @@ -802,9 +818,10 @@ not the base branch's flakiness. - The PR is unmistakably THIS workflow's own: `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). -- You reached this gate from Step 3 (green) or Step 4 (**unrelated-flake**) — i.e. the - fix is NOT implicated in any red. If Step 4 classified the red as **caused by the - fix** (ADVANCE), do NOT run this gate — advance the attempt instead. +- You reached this gate from Step 3 (green), Step 4 (**unrelated-flake**), or the Step 3.5 + gate-2 **target-focused fast-path** (2a) — i.e. the fix is NOT implicated in any red that + has concluded. If Step 4 classified a red as **caused by the fix** (ADVANCE), do NOT run + this gate — advance the attempt instead. **T1 — Identify the target test(s).** From the `[ci-scan-net11]` issue signature the fix addresses (and the PR's own diff), extract the fully-qualified test method name(s) the diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index a04910f74993..688db11db769 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5d24a1cd488401c009ba5daff2dc242dcd7a6bd10ccebbea660d48d8efd8af53","body_hash":"f0ad185861452d572741ea74303af7591f4534a56ad2d12a7baa68f2427b0402","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5d24a1cd488401c009ba5daff2dc242dcd7a6bd10ccebbea660d48d8efd8af53","body_hash":"c9d7bc71235656ca9f96b56fab03d58b332bdae28aa97573cc7d67d4887340d1","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 0eafaa7b7161..66c9de9715a1 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -706,14 +706,29 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: 1. **Human engaged.** If `C.humanEngaged` → `skipped: human engaged on PR #

; deferring` and stop. Never fight a human reviewer — the intentional hand-off boundary still holds the moment a person touches the PR. -2. **CI not settled / unknown / incomplete prefetch.** If `C.checksSettled == false` - OR `C.overallConclusion` is `pending`, `neutral`, or `unknown`, OR - `C.dataComplete == false` → the fix's CI has not finished on the current head SHA - (`C.headSha`), or the prefetch could not fully read this PR (a partial read can - understate `humanEngaged` / `attempt`). `skipped: PR #

CI pending / prefetch - incomplete on ; waiting` and stop. *(Round 1: this is where a - maintainer `/azp run` is awaited — the `/azp`-gated uitests/devicetests legs will - not have run until a human kicks them.)* +2. **CI not settled — but validate the target test first (target-focused readiness).** + If `C.checksSettled == false` OR `C.overallConclusion` is `pending`, `neutral`, or + `unknown`, OR `C.dataComplete == false` → the *overall* build has not finished on the + current head SHA (`C.headSha`), or the prefetch could not fully read this PR (a partial + read can understate `humanEngaged` / `attempt`). Unrelated legs still draining must NOT + keep an already-proven fix parked as a draft, so before waiting, try the target-focused + fast-path: + - **2a — Target-green fast-path (draft `[ci-fix]` PRs only).** If `C.dataComplete == + true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix] ` title prefix AND the + `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: identify + the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target test is + **VALIDATED-GREEN** (`Passed` on ≥1 leg, `Failed` on NO leg) AND every leg in + `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / + Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven + regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) + and stop. This early-out NEVER advances an attempt and NEVER acts on a red that could + be the fix's fault. + - **2b — Otherwise WAIT.** If the target test has not yet executed (pending/absent on + its leg), or a completed red is (or may be) caused by the fix, or `C.dataComplete == + false`, or this PR has no identifiable target test → `skipped: PR #

CI pending / + target not yet validated on ; waiting` and stop. *(Round 1: this is where a + maintainer `/azp run` is awaited — the `/azp`-gated uitests/devicetests legs will not + have run until a human kicks them.)* 3. **Green → surface for review.** If `C.overallConclusion == "success"`: the checks that RAN are green. **Primary-gate check first:** the deterministic `success` verdict only certifies "at least one green check, nothing failing or @@ -777,8 +792,9 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: #### Step 3.6 — Target-test verification & mark-ready gate -Reached from the Step 3 **green-surface** branch and the Step 4 **unrelated-flake** -branch, AFTER that branch has posted its comment. Purpose: confirm the SPECIFIC +Reached from the Step 3 **green-surface** branch, the Step 4 **unrelated-flake** branch +(AFTER that branch has posted its comment), and the Step 3.5 **gate-2 target-focused +fast-path** (2a — while unrelated legs are still pending). Purpose: confirm the SPECIFIC test(s) this PR was opened to fix now PASS in the PR's own CI, and — only when they do — transition the draft `[ci-fix]` PR to **ready for review** so a maintainer sees a validated fix instead of a draft. This is the ONLY place the loop flips draft→ready; it @@ -792,9 +808,10 @@ not the base branch's flakiness. - The PR is unmistakably THIS workflow's own: `[ci-fix] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). -- You reached this gate from Step 3 (green) or Step 4 (**unrelated-flake**) — i.e. the - fix is NOT implicated in any red. If Step 4 classified the red as **caused by the - fix** (ADVANCE), do NOT run this gate — advance the attempt instead. +- You reached this gate from Step 3 (green), Step 4 (**unrelated-flake**), or the Step 3.5 + gate-2 **target-focused fast-path** (2a) — i.e. the fix is NOT implicated in any red that + has concluded. If Step 4 classified a red as **caused by the fix** (ADVANCE), do NOT run + this gate — advance the attempt instead. **T1 — Identify the target test(s).** From the `[ci-scan]` issue signature the fix addresses (and the PR's own diff), extract the fully-qualified test method name(s) the From 1573fd9a30925106b94b91dd8390978bd6e84e2f Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:37:15 -0500 Subject: [PATCH 04/12] ci-fix: require cross-platform green + add p/0 label on mark-ready MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strengthen the Step 3.6 target-test readiness gate and the Step 3.5 gate-2 target-focused fast-path so the loop only flips a draft [ci-fix] PR to ready-for-review when the modified test passes on EVERY platform it runs on — not just the one leg that was originally red. A UI fix that repairs Android must not silently regress the same test on iOS / Windows / macOS. VALIDATED-GREEN now requires: Passed on every platform leg whose results contain the test, Failed on none, and no target platform leg still pending/unverified (any pending target leg -> WAIT for /azp run rather than mark ready). Also add a new add-labels safe-output (allowlisted to ONLY p/0) and emit it in Step 3.6 T3 alongside the mark-ready + comment, so a validated review-ready fix lands in the team's p/0 priority queue instead of the draft backlog. The already-ready idempotency branch now reconciles the label too (adds p/0 if a previously-marked-ready PR lacks it), and the dry-run path tallies would-label. Mirrored to both twins; Hard-Rule 6 allowed-outputs list updated to include mark_pull_request_as_ready_for_review and add_labels. Both locks recompiled (0/0, v0.80.9): add_labels config keeps allowed:[p/0] + required-title-prefix + required-labels (all hard-enforced by the handler); no action/permission drift. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 52 +++++--- .github/workflows/ci-status-fix-net11.md | 114 +++++++++++++----- .github/workflows/ci-status-fix.lock.yml | 52 +++++--- .github/workflows/ci-status-fix.md | 114 +++++++++++++----- 4 files changed, 242 insertions(+), 90 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 810f7dcad0a4..70e891de0dfc 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0506d309b131c4784d554cf9f57f5e22f79aad5683fc8496493159b438eb5079","body_hash":"34f301acea63c8adbb08b9b182be68dca7c8053342240d85d6499919b2f5c4f2","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"3ea0453ab3e02c7b20b09127ae3fa4a771930e25e63e273897e2ea8d1e5daf5b","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -275,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' + cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' - GH_AW_PROMPT_b6fb3c86775391af_EOF + GH_AW_PROMPT_af8900fc66cc33d2_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_b6fb3c86775391af_EOF' + cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_b6fb3c86775391af_EOF + Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_af8900fc66cc33d2_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' + cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' - GH_AW_PROMPT_b6fb3c86775391af_EOF + GH_AW_PROMPT_af8900fc66cc33d2_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' + cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -334,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_b6fb3c86775391af_EOF + GH_AW_PROMPT_af8900fc66cc33d2_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_b6fb3c86775391af_EOF' + cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' {{#runtime-import .github/workflows/ci-status-fix-net11.md}} - GH_AW_PROMPT_b6fb3c86775391af_EOF + GH_AW_PROMPT_af8900fc66cc33d2_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -562,15 +562,16 @@ 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_d98051e1082451f2_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_d98051e1082451f2_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_597f4682f79cc45e_EOF' + {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_597f4682f79cc45e_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", + "add_labels": " CONSTRAINTS: Maximum 3 label(s) can be added. Only these labels are allowed: [\"p/0\"]. Target: *.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix-net11] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", "push_to_pull_request_branch": " CONSTRAINTS: Maximum 3 push(es) can be made. The target pull request title must start with \"[ci-fix-net11] \".", @@ -603,6 +604,25 @@ jobs: } } }, + "add_labels": { + "defaultMax": 5, + "fields": { + "item_number": { + "issueNumberOrTemporaryId": true + }, + "labels": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, "create_pull_request": { "defaultMax": 1, "fields": { @@ -1944,7 +1964,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index f6530fcd78f8..93866b970896 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -298,6 +298,26 @@ safe-outputs: # scope controls; verify against the lock after compiling.) required-title-prefix: "[ci-fix-net11] " required-labels: [agentic-workflows] + add-labels: + # Apply the p/0 priority label to a [ci-fix-net11] PR at the exact moment the loop flips + # it from draft to ready-for-review (Step 3.6 T3) — so a validated, review-ready fix lands + # in the team's p/0 triage queue instead of sitting unseen in the draft backlog. Paired + # 1:1 with mark-pull-request-as-ready-for-review; target "*" lets the agent name the PR + # it just validated. + # allowed = HARD allowlist: the agent may ONLY ever add p/0, nothing else. This caps the + # blast radius of a confused/prompt-injected agent to exactly one benign priority label — + # it can never apply a downstream-triggering or destructive label. + allowed: [p/0] + # PER-RUN total (not per-PR): a sweep may mark several PRs ready in one run; each adds + # one label, so this matches the mark-ready per-run cap (3). + max: 3 + target: "*" + # Hard constraint (defense-in-depth): only ever label THIS workflow's own ci-fix PRs — + # [ci-fix-net11] title prefix AND agentic-workflows label. (If the v0.80.9 compiler drops + # these — as documented for update-pull-request above — the Step 3.6 preconditions + + # min-integrity:approved + the allowed:[p/0] allowlist are the compensating controls.) + required-title-prefix: "[ci-fix-net11] " + required-labels: [agentic-workflows] timeout-minutes: 90 @@ -376,21 +396,26 @@ through `safe-outputs`. 6. **All writes via `safe-outputs`.** Allowed outputs: `create_pull_request` (first attempt only), `push_to_pull_request_branch` (advance an existing PR by one attempt), `update_pull_request` (bump the attempt marker / refresh the - prior-attempts table), and `add_comment` (progress notes on the `[ci-fix-net11]` PR - ONLY). NEVER comment on the tracking issue (issues are locked by + prior-attempts table), `add_comment` (progress notes on the `[ci-fix-net11]` PR + ONLY), `mark_pull_request_as_ready_for_review` (flip a target-validated draft + `[ci-fix-net11]` PR from draft to ready — Step 3.6 T3 only), and `add_labels` + (add ONLY the `p/0` label, ONLY on that same draft→ready transition — Step 3.6 + T3). NEVER comment on the tracking issue (issues are locked by `.github/workflows/ci-scan-lock-issues.yml`) — `add_comment` targets the PR. No `gh pr create`, no manual `git push`. **Defense-in-depth:** `add_comment` and `update_pull_request` use `target: "*"` (the agent supplies the PR number). - `add_comment` is now config-locked to `required-title-prefix: "[ci-fix-net11] "` + + `add_comment`, `mark_pull_request_as_ready_for_review`, and `add_labels` are + config-locked to `required-title-prefix: "[ci-fix-net11] "` + `required-labels: [agentic-workflows]` (hard-enforced by the handler, same as - `push_to_pull_request_branch`), so a comment can only ever land on THIS - workflow's own PRs. `update_pull_request` CANNOT be config-locked to a - title/label in gh-aw v0.79.8 (the compiler silently drops `required-*` for that - output — verified against the lock), so it keeps `title: false` (no retitles; - body-marker edits only) plus this prompt-level guard. Before emitting either, - VERIFY the target PR carries BOTH the `[ci-fix-net11]` title prefix AND the - `agentic-workflows` label; never comment on or edit the body of any PR that - lacks both. + `push_to_pull_request_branch`), and `add_labels` additionally has an + `allowed: [p/0]` allowlist so it can ONLY ever add `p/0` — so these can only + ever land on THIS workflow's own PRs. `update_pull_request` CANNOT be + config-locked to a title/label in gh-aw v0.79.8 (the compiler silently drops + `required-*` for that output — verified against the lock), so it keeps + `title: false` (no retitles; body-marker edits only) plus this prompt-level + guard. Before emitting ANY of these, VERIFY the target PR carries BOTH the + `[ci-fix-net11]` title prefix AND the `agentic-workflows` label; never comment + on, edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, `add_comment` 3, `update_pull_request` 3. Note an ADVANCE spends one push **and** @@ -727,7 +752,9 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: == true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: identify the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target - test is **VALIDATED-GREEN** (`Passed` on ≥1 leg, `Failed` on NO leg) AND every leg in + test is **VALIDATED-GREEN** (per T2's all-platform definition below — the target test + PASSES on every platform leg that ran it, `Failed` on none, and no *target* platform + leg is still pending) AND every leg in `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) @@ -844,34 +871,63 @@ ORG=dnceng-public; PROJ=public; P=; BUILD= # test runs for the build: curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' -# per run id, look for each target test's outcome (repeat per target test): +# per run id, look for each target test's outcome (repeat per target test). +# IMPORTANT: aggregate outcomes across EVERY platform leg's run (Android/iOS/Windows/ +# macOS) — the test must PASS on all platforms it runs on, not just the one that was red: curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' ``` -Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it appears with -`outcome == "Passed"` on at least one platform leg AND appears with `outcome == -"Failed"` on NO leg. A target test that never appears at all (**not executed** — e.g. an -`/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been kicked) is -NOT validated: record `skipped: target test not yet executed on PR #

-( not run — needs /azp run)` and stop this gate WITHOUT marking ready. Do NOT -overclaim — a green *sibling* leg in the same group is not the target test. +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it PASSES on **every +platform it runs on** — a fix that repairs one platform must not silently regress the same +test on another, so a pass on the originally-red leg alone is NOT enough. Across the target +pipeline's platform legs (for a UI test: the Android, iOS, Windows, and macOS/MacCatalyst +legs of `maui-pr-uitests`; for a device test: each device-test platform), require ALL of: +- the target test appears with `outcome == "Passed"` on **every** platform leg whose + results contain it, AND +- it appears with `outcome == "Failed"` (or aborted/errored) on **NO** leg, AND +- **no platform is left unverified.** For each platform family the target pipeline covers, + that platform's leg must have CONCLUDED on `C.headSha`. If a platform leg concluded and + its results simply do not contain the test, the test does not run on that platform — that + is fine, not a gap. But if a platform leg that *would* run the test has **not concluded** + (pending, or an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been + kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet validated + across platforms: record `skipped: target test green on but not yet + verified on (leg(s) pending / need /azp run) on PR #

` and + stop this gate WITHOUT marking ready. + +A target test that never appears on ANY concluded leg (**not executed** anywhere — e.g. its +`/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: +target test not yet executed on PR #

( not run — needs /azp run)` and stop +this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in the same group +is not the target test, and a pass on one platform is not a pass on the others. **T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` - comment for THIS head SHA already exists (or `C.isDraft` is already false), record - `already-marked-ready PR #

(head )` and stop. +- **Idempotency + label reconcile:** the draft→ready transition is one-shot — if a prior + bot `🎯 … target test … validated … on ` comment for THIS head SHA already + exists, OR `C.isDraft` is already false, do NOT re-comment and do NOT re-mark ready. But + still reconcile the priority label so a validated fix always lands in the p/0 queue: read + the PR's current labels; if it is MISSING `p/0`, emit a single `add_labels` `["p/0"]` for + PR #

(subject to the same Step 0 dry-run gate — under `dry_run == "true"` tally + `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR + #

(already-ready)`; if it already carries `p/0`, record `already-marked-ready PR #

+ (head )`. Then stop. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended - readiness comment and "would mark ready" to the run log, tally `dry-run: + readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. -- Otherwise emit BOTH safe-outputs for THIS PR number `

`: +- Otherwise emit THREE safe-outputs for THIS PR number `

`: 1. `add_comment`: `🎯 Target test validated green on - passed (, buildId ). — not caused by this fix."> Transitioning this PR - from draft to ready for review; a maintainer still reviews and merges.` + passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> + Transitioning this PR from draft to ready for review and adding `p/0`; a maintainer + still reviews and merges.` 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. -- Record `marked-ready PR #

(target green on )` and stop. + 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into + the team's p/0 priority queue so it is triaged, not lost in the draft backlog. (If + the PR somehow already carries `p/0`, this is a harmless no-op.) +- Record `marked-ready PR #

(target green on ALL platforms on , + labeled p/0)` and stop. #### Step 3.5.R — Maintainer change-request response (Track C) diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 688db11db769..d3a9a1369492 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5d24a1cd488401c009ba5daff2dc242dcd7a6bd10ccebbea660d48d8efd8af53","body_hash":"c9d7bc71235656ca9f96b56fab03d58b332bdae28aa97573cc7d67d4887340d1","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"11dddc1285ad787ae5216bbde5cf19a7aa1f9efa0bce85cd3307911500c0f466","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -275,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' + cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' - GH_AW_PROMPT_25e949294484c30e_EOF + GH_AW_PROMPT_72573af5f11317cd_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_25e949294484c30e_EOF' + cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_25e949294484c30e_EOF + Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_72573af5f11317cd_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' + cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' - GH_AW_PROMPT_25e949294484c30e_EOF + GH_AW_PROMPT_72573af5f11317cd_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' + cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -334,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_25e949294484c30e_EOF + GH_AW_PROMPT_72573af5f11317cd_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_25e949294484c30e_EOF' + cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' {{#runtime-import .github/workflows/ci-status-fix.md}} - GH_AW_PROMPT_25e949294484c30e_EOF + GH_AW_PROMPT_72573af5f11317cd_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -556,15 +556,16 @@ 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_6c81318c84474248_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_6c81318c84474248_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_e0cb359b55d46650_EOF' + {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_e0cb359b55d46650_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", + "add_labels": " CONSTRAINTS: Maximum 3 label(s) can be added. Only these labels are allowed: [\"p/0\"]. Target: *.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", "push_to_pull_request_branch": " CONSTRAINTS: Maximum 3 push(es) can be made. The target pull request title must start with \"[ci-fix] \".", @@ -597,6 +598,25 @@ jobs: } } }, + "add_labels": { + "defaultMax": 5, + "fields": { + "item_number": { + "issueNumberOrTemporaryId": true + }, + "labels": { + "required": true, + "type": "array", + "itemType": "string", + "itemSanitize": true, + "itemMaxLength": 128 + }, + "repo": { + "type": "string", + "maxLength": 256 + } + } + }, "create_pull_request": { "defaultMax": 1, "fields": { @@ -1931,7 +1951,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 66c9de9715a1..65d32211a4cc 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -288,6 +288,26 @@ safe-outputs: # controls; verify against the lock after compiling.) required-title-prefix: "[ci-fix] " required-labels: [agentic-workflows] + add-labels: + # Apply the p/0 priority label to a [ci-fix] PR at the exact moment the loop flips it + # from draft to ready-for-review (Step 3.6 T3) — so a validated, review-ready fix lands + # in the team's p/0 triage queue instead of sitting unseen in the draft backlog. Paired + # 1:1 with mark-pull-request-as-ready-for-review; target "*" lets the agent name the PR + # it just validated. + # allowed = HARD allowlist: the agent may ONLY ever add p/0, nothing else. This caps the + # blast radius of a confused/prompt-injected agent to exactly one benign priority label — + # it can never apply a downstream-triggering or destructive label. + allowed: [p/0] + # PER-RUN total (not per-PR): a sweep may mark several PRs ready in one run; each adds + # one label, so this matches the mark-ready per-run cap (3). + max: 3 + target: "*" + # Hard constraint (defense-in-depth): only ever label THIS workflow's own ci-fix PRs — + # [ci-fix] title prefix AND agentic-workflows label. (If the v0.80.9 compiler drops these + # — as documented for update-pull-request above — the Step 3.6 preconditions + + # min-integrity:approved + the allowed:[p/0] allowlist are the compensating controls.) + required-title-prefix: "[ci-fix] " + required-labels: [agentic-workflows] timeout-minutes: 90 @@ -366,21 +386,26 @@ through `safe-outputs`. 6. **All writes via `safe-outputs`.** Allowed outputs: `create_pull_request` (first attempt only), `push_to_pull_request_branch` (advance an existing PR by one attempt), `update_pull_request` (bump the attempt marker / refresh the - prior-attempts table), and `add_comment` (progress notes on the `[ci-fix]` PR - ONLY). NEVER comment on the tracking issue (issues are locked by + prior-attempts table), `add_comment` (progress notes on the `[ci-fix]` PR + ONLY), `mark_pull_request_as_ready_for_review` (flip a target-validated draft + `[ci-fix]` PR from draft to ready — Step 3.6 T3 only), and `add_labels` (add + ONLY the `p/0` label, ONLY on that same draft→ready transition — Step 3.6 T3). + NEVER comment on the tracking issue (issues are locked by `.github/workflows/ci-scan-lock-issues.yml`) — `add_comment` targets the PR. No `gh pr create`, no manual `git push`. **Defense-in-depth:** `add_comment` and `update_pull_request` use `target: "*"` (the agent supplies the PR number). - `add_comment` is now config-locked to `required-title-prefix: "[ci-fix] "` + + `add_comment`, `mark_pull_request_as_ready_for_review`, and `add_labels` are + config-locked to `required-title-prefix: "[ci-fix] "` + `required-labels: [agentic-workflows]` (hard-enforced by the handler, same as - `push_to_pull_request_branch`), so a comment can only ever land on THIS - workflow's own PRs. `update_pull_request` CANNOT be config-locked to a - title/label in gh-aw v0.79.8 (the compiler silently drops `required-*` for that - output — verified against the lock), so it keeps `title: false` (no retitles; - body-marker edits only) plus this prompt-level guard. Before emitting either, - VERIFY the target PR carries BOTH the `[ci-fix]` title prefix AND the - `agentic-workflows` label; never comment on or edit the body of any PR that - lacks both. + `push_to_pull_request_branch`), and `add_labels` additionally has an + `allowed: [p/0]` allowlist so it can ONLY ever add `p/0` — so these can only + ever land on THIS workflow's own PRs. `update_pull_request` CANNOT be + config-locked to a title/label in gh-aw v0.79.8 (the compiler silently drops + `required-*` for that output — verified against the lock), so it keeps + `title: false` (no retitles; body-marker edits only) plus this prompt-level + guard. Before emitting ANY of these, VERIFY the target PR carries BOTH the + `[ci-fix]` title prefix AND the `agentic-workflows` label; never comment on, + edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, `add_comment` 3, `update_pull_request` 3. Note an ADVANCE spends one push **and** @@ -717,7 +742,9 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix] ` title prefix AND the `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: identify the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target test is - **VALIDATED-GREEN** (`Passed` on ≥1 leg, `Failed` on NO leg) AND every leg in + **VALIDATED-GREEN** (per T2's all-platform definition below — the target test PASSES + on every platform leg that ran it, `Failed` on none, and no *target* platform leg is + still pending) AND every leg in `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) @@ -834,34 +861,63 @@ ORG=dnceng-public; PROJ=public; P=; BUILD= # test runs for the build: curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' -# per run id, look for each target test's outcome (repeat per target test): +# per run id, look for each target test's outcome (repeat per target test). +# IMPORTANT: aggregate outcomes across EVERY platform leg's run (Android/iOS/Windows/ +# macOS) — the test must PASS on all platforms it runs on, not just the one that was red: curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' ``` -Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it appears with -`outcome == "Passed"` on at least one platform leg AND appears with `outcome == -"Failed"` on NO leg. A target test that never appears at all (**not executed** — e.g. an -`/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been kicked) is -NOT validated: record `skipped: target test not yet executed on PR #

-( not run — needs /azp run)` and stop this gate WITHOUT marking ready. Do NOT -overclaim — a green *sibling* leg in the same group is not the target test. +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it PASSES on **every +platform it runs on** — a fix that repairs one platform must not silently regress the same +test on another, so a pass on the originally-red leg alone is NOT enough. Across the target +pipeline's platform legs (for a UI test: the Android, iOS, Windows, and macOS/MacCatalyst +legs of `maui-pr-uitests`; for a device test: each device-test platform), require ALL of: +- the target test appears with `outcome == "Passed"` on **every** platform leg whose + results contain it, AND +- it appears with `outcome == "Failed"` (or aborted/errored) on **NO** leg, AND +- **no platform is left unverified.** For each platform family the target pipeline covers, + that platform's leg must have CONCLUDED on `C.headSha`. If a platform leg concluded and + its results simply do not contain the test, the test does not run on that platform — that + is fine, not a gap. But if a platform leg that *would* run the test has **not concluded** + (pending, or an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been + kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet validated + across platforms: record `skipped: target test green on but not yet + verified on (leg(s) pending / need /azp run) on PR #

` and + stop this gate WITHOUT marking ready. + +A target test that never appears on ANY concluded leg (**not executed** anywhere — e.g. its +`/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: +target test not yet executed on PR #

( not run — needs /azp run)` and stop +this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in the same group +is not the target test, and a pass on one platform is not a pass on the others. **T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` - comment for THIS head SHA already exists (or `C.isDraft` is already false), record - `already-marked-ready PR #

(head )` and stop. +- **Idempotency + label reconcile:** the draft→ready transition is one-shot — if a prior + bot `🎯 … target test … validated … on ` comment for THIS head SHA already + exists, OR `C.isDraft` is already false, do NOT re-comment and do NOT re-mark ready. But + still reconcile the priority label so a validated fix always lands in the p/0 queue: read + the PR's current labels; if it is MISSING `p/0`, emit a single `add_labels` `["p/0"]` for + PR #

(subject to the same Step 0 dry-run gate — under `dry_run == "true"` tally + `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR + #

(already-ready)`; if it already carries `p/0`, record `already-marked-ready PR #

+ (head )`. Then stop. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended - readiness comment and "would mark ready" to the run log, tally `dry-run: + readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. -- Otherwise emit BOTH safe-outputs for THIS PR number `

`: +- Otherwise emit THREE safe-outputs for THIS PR number `

`: 1. `add_comment`: `🎯 Target test validated green on - passed (, buildId ). — not caused by this fix."> Transitioning this PR - from draft to ready for review; a maintainer still reviews and merges.` + passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> + Transitioning this PR from draft to ready for review and adding `p/0`; a maintainer + still reviews and merges.` 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. -- Record `marked-ready PR #

(target green on )` and stop. + 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into + the team's p/0 priority queue so it is triaged, not lost in the draft backlog. (If + the PR somehow already carries `p/0`, this is a harmless no-op.) +- Record `marked-ready PR #

(target green on ALL platforms on , + labeled p/0)` and stop. #### Step 3.5.R — Maintainer change-request response (Track C) From 9d416840582c2f2203baba328cc88dbf7d922905 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:39:36 -0500 Subject: [PATCH 05/12] ci-fix: reconcile p/0 in the already-ready precondition (testable + robust) The Step 3.6 preconditions stop with "already-ready" for any non-draft PR BEFORE reaching the T3 mark-ready path, so the p/0 label-reconcile added in the prior commit could never fire for a PR that was already flipped to ready. Move the reconcile into the already-ready precondition itself: an already-ready [ci-fix] PR (correct title + agentic-workflows label) that is missing p/0 now gets it added there. This makes every already-marked-ready loop PR self-heal to carry p/0, and makes the label path testable on PRs that are already ready (e.g. #36429). T3's idempotency is simplified to defer label reconciliation to that precondition. Mirrored to both twins; locks recompiled (0/0, body_hash only). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 22 ++++++++++--------- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 22 ++++++++++--------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 70e891de0dfc..cfef9e583417 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"3ea0453ab3e02c7b20b09127ae3fa4a771930e25e63e273897e2ea8d1e5daf5b","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"c8601ecaa9aa14dd129f8246cd63a1962e21d17f693bf8be047b95c18d6fbe60","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 93866b970896..0d3cd7855fc4 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -841,7 +841,14 @@ not the base branch's flakiness. **Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

()` and stop this gate): -- `C.isDraft == true` — if the PR is already ready, record `already-ready PR #

` and stop. +- `C.isDraft == true` — if the PR is already ready-for-review, the draft→ready + transition is already done; do NOT re-mark. But still reconcile the priority label so + every validated loop PR carries it: if this PR is unmistakably THIS workflow's own + (`[ci-fix-net11] ` title prefix AND the `agentic-workflows` label) and is MISSING `p/0`, + emit a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — + under `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and + record `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR + #

`. Either way, stop this gate. - The PR is unmistakably THIS workflow's own: `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -903,15 +910,10 @@ this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in t is not the target test, and a pass on one platform is not a pass on the others. **T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency + label reconcile:** the draft→ready transition is one-shot — if a prior - bot `🎯 … target test … validated … on ` comment for THIS head SHA already - exists, OR `C.isDraft` is already false, do NOT re-comment and do NOT re-mark ready. But - still reconcile the priority label so a validated fix always lands in the p/0 queue: read - the PR's current labels; if it is MISSING `p/0`, emit a single `add_labels` `["p/0"]` for - PR #

(subject to the same Step 0 dry-run gate — under `dry_run == "true"` tally - `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR - #

(already-ready)`; if it already carries `p/0`, record `already-marked-ready PR #

- (head )`. Then stop. +- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` + comment for THIS head SHA already exists, the mark-ready already ran for this head — + record `already-marked-ready PR #

(head )` and stop (the already-ready + precondition above handles p/0 label reconciliation for PRs already flipped to ready). - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index d3a9a1369492..e899733fe4ec 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"11dddc1285ad787ae5216bbde5cf19a7aa1f9efa0bce85cd3307911500c0f466","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"d6e79d35df7389a64d6aeb096818db2ba892e8ae8b2bc9646cb9c107a4fe54b4","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 65d32211a4cc..676f3044a9e5 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -831,7 +831,14 @@ not the base branch's flakiness. **Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

()` and stop this gate): -- `C.isDraft == true` — if the PR is already ready, record `already-ready PR #

` and stop. +- `C.isDraft == true` — if the PR is already ready-for-review, the draft→ready + transition is already done; do NOT re-mark. But still reconcile the priority label so + every validated loop PR carries it: if this PR is unmistakably THIS workflow's own + (`[ci-fix] ` title prefix AND the `agentic-workflows` label) and is MISSING `p/0`, emit + a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — under + `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and record + `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR #

`. + Either way, stop this gate. - The PR is unmistakably THIS workflow's own: `[ci-fix] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -893,15 +900,10 @@ this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in t is not the target test, and a pass on one platform is not a pass on the others. **T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency + label reconcile:** the draft→ready transition is one-shot — if a prior - bot `🎯 … target test … validated … on ` comment for THIS head SHA already - exists, OR `C.isDraft` is already false, do NOT re-comment and do NOT re-mark ready. But - still reconcile the priority label so a validated fix always lands in the p/0 queue: read - the PR's current labels; if it is MISSING `p/0`, emit a single `add_labels` `["p/0"]` for - PR #

(subject to the same Step 0 dry-run gate — under `dry_run == "true"` tally - `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR - #

(already-ready)`; if it already carries `p/0`, record `already-marked-ready PR #

- (head )`. Then stop. +- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` + comment for THIS head SHA already exists, the mark-ready already ran for this head — + record `already-marked-ready PR #

(head )` and stop (the already-ready + precondition above handles p/0 label reconciliation for PRs already flipped to ready). - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. From 45a45f006837acc57598463bf9e88afe6579bfaa Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Wed, 8 Jul 2026 18:15:08 -0500 Subject: [PATCH 06/12] ci-fix: harden Step 3.6 mark-ready loop (adversarial-review consensus) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Apply the consensus fixes from a 3-model adversarial self-review of the draft->ready (Step 3.6) capability, mirrored identically to BOTH twins (ci-status-fix.md + ci-status-fix-net11.md; only [ci-fix]<->[ci-fix-net11] and main<->net11.0 cross-refs differ). Headline correctness fixes: - T2 per-test validation was UNREACHABLE: _apis/test/... 302-redirects to a sign-in HTML page anonymously (Hard-Rule 8), so every target test looked "not executed" and the gate could never fire. Rewrite T2 to anonymous, leg-level validation via _apis/build/builds/{id}/timeline (HTTP 200 JSON) -- a succeeded category leg is a strictly stronger green bar. Applied to BOTH twins (net11 still carried the old forbidden _apis/test curls). - Gate 3 (green-surface) and Gate 4 (red-classify) idempotency/dry-run guards used to `stop` BEFORE Step 3.6. Because /azp-gated legs conclude LATER on the SAME head SHA (an /azp run adds no commit) and Step 3.6 is the ONLY draft->ready flip point, a cross-platform-validated PR could never be marked ready. Now the comment is suppressed (SKIP_SURFACE_COMMENT / SKIP_FLAKE_COMMENT) but the gate ALWAYS falls through to run Step 3.6 every sweep. Also unblocks the dry-run p/0 preview for already-ready PRs. - T3 mark-ready: decouple comment idempotency from the mark-ready (SUPPRESS_COMMENT flag -- a stale 🎯 comment while still draft means the prior mark-ready did NOT take, so re-mark and suppress only the duplicate comment) + add an all-or-nothing atomicity budget pre-check so a PR is never marked ready/labeled without its 🎯 audit comment. Supporting hardening: - Hard-Rule 7: enumerate the new per-run caps (mark_pull_request_as_ready_for_review, add_labels counts LABELS) and document the mark-ready all-or-nothing set. - Gate-2a: sync wording to the timeline method and tighten to "no target platform family the pipeline covers is still unconcluded". - Reconcile precondition: note the shared add_labels budget deferral. - Query-CiFixPRs.ps1: cross-reference $LoopBotCommitAuthors <-> $BotLogins maintenance note. Both locks recompiled 0/0 (body_hash-only delta; v0.80.9 pin held; no action/permission drift). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Query-CiFixPRs.ps1 | 5 + .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 225 +++++++++++------- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 225 +++++++++++------- 5 files changed, 289 insertions(+), 170 deletions(-) diff --git a/.github/scripts/Query-CiFixPRs.ps1 b/.github/scripts/Query-CiFixPRs.ps1 index 93c38ba2381d..54836a4a2003 100755 --- a/.github/scripts/Query-CiFixPRs.ps1 +++ b/.github/scripts/Query-CiFixPRs.ps1 @@ -74,6 +74,11 @@ $LoopBotCommitAuthors = @( 'github-actions', 'app/github-actions' ) +# MAINTENANCE: if this workflow's bot identity ever changes (new GitHub App, renamed +# bot), update BOTH lists — $BotLogins (comment/review-author filtering, ~line 27) AND +# $LoopBotCommitAuthors (commit-author carve-out, above). They are intentionally +# separate ($LoopBotCommitAuthors is the narrower "our own commit authors" set), so a +# new identity added to one but not the other silently drifts the human-engagement gate. # NOTE: 'action_required' is deliberately EXCLUDED. That conclusion means a human # must act (an Actions approval gate, or an integration awaiting a manual run) — # it reports status=completed, so treating it as a failure would let a settled head diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index cfef9e583417..c19246d454ef 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"c8601ecaa9aa14dd129f8246cd63a1962e21d17f693bf8be047b95c18d6fbe60","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"1dfa097f616b04e3563d01a0cbee4eaa595acd52c5a5629e1b485976af39670d","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 0d3cd7855fc4..a9c2bf8a6868 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -418,9 +418,13 @@ through `safe-outputs`. on, edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, - `add_comment` 3, `update_pull_request` 3. Note an ADVANCE spends one push **and** - one update **and** one comment, so ≤ 3 advances/run; surfacing a green or - annotating a flake spends one comment. When a bucket is exhausted, do NOT keep + `add_comment` 3, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` + 3, `add_labels` 3 (counts LABELS, not calls). Note an ADVANCE spends one push + **and** one update **and** one comment, so ≤ 3 advances/run; surfacing a green or + annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** spends one + comment **and** one mark-ready **and** one label as an ALL-OR-NOTHING set (T3 + pre-checks those buckets and defers the whole PR if any is exhausted — never mark + a PR ready without its 🎯 audit comment). When a bucket is exhausted, do NOT keep emitting (extras are silently dropped) — record `skipped: per-run cap reached; deferring PR #

to next cycle` for each remaining PR so the drop is a deliberate, logged decision. The continuous loop picks the deferred PRs up next @@ -751,10 +755,13 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: - **2a — Target-green fast-path (draft `[ci-fix-net11]` PRs only).** If `C.dataComplete == true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: - identify the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target - test is **VALIDATED-GREEN** (per T2's all-platform definition below — the target test - PASSES on every platform leg that ran it, `Failed` on none, and no *target* platform - leg is still pending) AND every leg in + identify the target test(s) and read the PR's OWN build **timeline / per-leg status** + (anonymous `_apis/build` — never `_apis/test`, per Hard-Rule 8). If EVERY target test + is **VALIDATED-GREEN** (per T2's all-platform definition below — the target's category + leg is `succeeded` on every platform that runs it, failed on none, and NO target + platform family the pipeline covers is still pending/unconcluded, per T2's "no platform + left unverified" rule; a platform that simply has no leg for the target's category — the + test doesn't run there — is fine, not a gap) AND every leg in `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) @@ -777,19 +784,27 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: #

primary CI gate (maui-pr) not green on ; waiting` and stop — do NOT surface. (The `/azp`-gated `maui-pr-uitests` (def 313) / `maui-pr-devicetests` (def 314) legs MAY still be un-run — that is expected and is named below, not a - reason to withhold the surface.) **Idempotency:** scan the PR's existing comments - for a prior bot `✅ … validated … on ` note for THIS head SHA — if one - already exists, record `already-surfaced PR #

(head )` and stop - WITHOUT re-commenting (re-surfacing the same green every tick is noise and burns - the per-run comment budget other PRs need). Otherwise resolve the attempt number from - `C.effectiveAttempt` (the authoritative max(marker, bot-commit) counter; omit the - number only if it is somehow indeterminate). **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `✅` validated-green body to the run log, tally `dry-run: would-surface-green PR #

`, and stop. Otherwise `add_comment` on PR #

: `✅ Attempt /10 - validated — the fix's CI is green on . Ready for human review.` - Name any `/azp`-gated legs (uitests def 313 / devicetests def 314) that have not - run and still need a maintainer `/azp run`. Do NOT advance. Record - `surfaced-green PR #

(attempt /10)`, then run **Step 3.6** - (target-test readiness gate) for this PR before stopping. *(This directly - attacks the real bottleneck — no reviews — so it is the highest-value outcome.)* + reason to withhold the surface.) **Comment idempotency + dry-run suppress the ✅ + comment ONLY — neither skips Step 3.6.** Scan the PR's existing comments for a prior + bot `✅ … validated … on ` note for THIS head SHA; if one exists, set + `SKIP_SURFACE_COMMENT = true`. Resolve the attempt number from `C.effectiveAttempt` + (the authoritative max(marker, bot-commit) counter; omit the number only if it is + somehow indeterminate). Then post the surface comment UNLESS suppressed: + - if `dry_run == "true"`: do NOT emit — print the intended `✅` validated-green body to + the run log and tally `dry-run: would-surface-green PR #

`; + - else if `SKIP_SURFACE_COMMENT`: do NOT re-post — record `already-surfaced PR #

+ (head )` (re-surfacing the same green every tick is noise and burns the + per-run comment budget other PRs need); + - else `add_comment` on PR #

: `✅ Attempt /10 validated — the fix's CI is + green on . Ready for human review.` naming any `/azp`-gated legs (uitests + def 313 / devicetests def 314) that have not run and still need a maintainer `/azp + run`; record `surfaced-green PR #

(attempt /10)`. + Do NOT advance. Then — in ALL of the above cases — run **Step 3.6** (target-test + readiness gate) for this PR before stopping: its `/azp`-gated target legs may conclude + green on this SAME head SHA on a LATER sweep (an `/azp run` adds no commit), and Step + 3.6 is the ONLY place the draft→ready flip happens, so it MUST re-evaluate every sweep — + never `stop` here before it. *(This directly attacks the real bottleneck — no reviews — + so it is the highest-value outcome.)* 4. **Red → classify caused-by-fix vs unrelated-flake.** If `C.overallConclusion == "failure"`, analyze the PR's OWN failing build (NOT `net11.0`): find the AzDO `maui-pr` build for this PR (filter builds by `branchName=refs/pull/

/merge`, @@ -797,19 +812,26 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: method and Step 4.7 flake buckets to `C.failedLegs`. - **Unrelated flake only** (every failed leg is known-flaky / infra / a pre-existing baseline red NOT introduced by the fix): do NOT burn an attempt. - **Idempotency first:** scan the PR's existing comments for a prior bot - `♻️ … unrelated flake … on ` note for THIS head SHA — if one already - exists, record `already-annotated-flake PR #

(head )` and stop - WITHOUT re-commenting (re-annotating the same flake every 12h sweep is noise and - burns the per-run comment budget other PRs need). Otherwise resolve the attempt - number from `C.effectiveAttempt` (the authoritative max(marker, bot-commit) - counter), omitting the `Attempt /10:` prefix only if it is somehow - indeterminate. **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `♻️` unrelated-flake body to the run log, tally `dry-run: would-annotate-flake PR #

`, and stop. Otherwise `add_comment` on PR #

: `♻️ Attempt /10: red is - unrelated flake on leg(s) () on ; the fix itself is not - implicated. A maintainer re-run (/azp run ) should clear it.` Record - `annotated-flake PR #

(head )`, then run **Step 3.6** - (target-test readiness gate) for this PR before stopping. *(Round 1: human re-runs; - Round 2: auto re-trigger.)* + **Comment idempotency + dry-run suppress the ♻️ comment ONLY — neither skips Step + 3.6.** Scan the PR's existing comments for a prior bot `♻️ … unrelated flake … on + ` note for THIS head SHA; if one exists, set `SKIP_FLAKE_COMMENT = true`. + Resolve the attempt number from `C.effectiveAttempt` (the authoritative max(marker, + bot-commit) counter), omitting the `Attempt /10:` prefix only if it is + somehow indeterminate. Then post the flake note UNLESS suppressed: + - if `dry_run == "true"`: do NOT emit — print the intended `♻️` unrelated-flake body + to the run log and tally `dry-run: would-annotate-flake PR #

`; + - else if `SKIP_FLAKE_COMMENT`: do NOT re-post — record `already-annotated-flake PR + #

(head )` (re-annotating the same flake every 12h sweep is noise and + burns the per-run comment budget other PRs need); + - else `add_comment` on PR #

: `♻️ Attempt /10: red is unrelated flake on + leg(s) () on ; the fix itself is not implicated. A + maintainer re-run (/azp run ) should clear it.` record `annotated-flake + PR #

(head )`. + Then — in ALL of the above cases — run **Step 3.6** (target-test readiness gate) for + this PR before stopping: its `/azp`-gated target legs may conclude green on this SAME + head SHA on a LATER sweep, and Step 3.6 is the ONLY place the draft→ready flip + happens, so it MUST re-evaluate every sweep — never `stop` here before it. *(Round 1: + human re-runs; Round 2: auto re-trigger.)* - **Caused by the fix** (a failed leg still matches the original target signature, or the fix introduced a NEW failure): advance an attempt. - **Attempt count.** `attempt = C.effectiveAttempt` — the authoritative @@ -848,7 +870,10 @@ not the base branch's flakiness. emit a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — under `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR - #

`. Either way, stop this gate. + #

`. This reconcile shares the per-run `add_labels` budget (Hard-Rule 7) with T3 + mark-ready transitions, which take priority — if the label bucket is already exhausted, do + NOT emit; record `skipped: p/0 reconcile deferred PR #

(add_labels cap)` (it self-heals + next sweep). Either way, stop this gate. - The PR is unmistakably THIS workflow's own: `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -865,64 +890,96 @@ test can be identified (e.g. a product build-break rather than a test failure), `skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix is validated by overall-green alone, which the Step 3 branch already handles. -**T2 — Drill into the PR's own build test-results.** Using the SAME build-discovery as -Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` or `sourceVersion == -C.headSha`), find the build(s) on `C.headSha` for the pipeline(s) that actually RUN the -target test — `maui-pr` (def 302) for unit/integration tests, `maui-pr-uitests` (def -313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device tests — then query -the AzDO test-results REST API on `dev.azure.com` for each target test's outcome on that -build: +**T2 — Verify the target test's platform legs are green (anonymous, leg-level).** Per-test +outcomes come from the AzDO **test-results** API (`_apis/test/...`), which is **NOT reachable +anonymously — Hard-Rule 8**: those endpoints 302-redirect to a sign-in page on this runner, so +a `curl` returns an HTML redirect (not JSON) and every target test would look "not executed". +Validate instead at **leg granularity** using ONLY the anonymous `_apis/build/...` timeline +(Hard-Rule 8) — which is a STRONGER bar anyway: a `succeeded` category leg means every test in +that category, including the target, passed on that platform (a de-flaked / target test is +never skipped, so a green category leg cannot hide a target-test failure). + +Map the target test to the CI leg(s) that run it. A leg name encodes platform + test category +(e.g. `Android UITests SafeAreaEdges,Shadow`, `iOS UITests SafeAreaEdges,Shadow`, `macOS +UITests SafeAreaEdges,Shadow`, `Windows UITests SafeAreaEdges,Shadow`). Determine the target +test's UI-test category — its `[Category(UITestCategories.X)]` in the test/HostApp source, +visible in the PR diff or the test file — to know which leg-name substring identifies its legs; +for a device test, the per-platform device-test legs. + +Using the SAME build-discovery as Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` +or `sourceVersion == C.headSha`), read each build's **timeline** on `C.headSha` for the +pipeline(s) that RUN the target test — `maui-pr` (def 302) for unit/integration tests, +`maui-pr-uitests` (def 313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device +tests: ```bash -ORG=dnceng-public; PROJ=public; P=; BUILD= -# test runs for the build: -curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ - | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' -# per run id, look for each target test's outcome (repeat per target test). -# IMPORTANT: aggregate outcomes across EVERY platform leg's run (Android/iOS/Windows/ -# macOS) — the test must PASS on all platforms it runs on, not just the one that was red: -curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ - | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' +ORG=dnceng-public; PROJ=public; BUILD= +# Anonymous + Hard-Rule-8-compliant. NEVER call _apis/test/... (it 302-redirects to sign-in). +# Each type=="Job" record is one platform leg: result (succeeded/failed/canceled/null), +# state (completed/inProgress/pending), name (encodes " UITests "): +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/build/builds/$BUILD/timeline?api-version=7.1" \ + | tee /tmp/gh-aw/agent/timeline_${BUILD}.json \ + | jq -r '.records[] | select(.type=="Job") | "\(.result)\t\(.state)\t\(.name)"' ``` -Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it PASSES on **every -platform it runs on** — a fix that repairs one platform must not silently regress the same -test on another, so a pass on the originally-red leg alone is NOT enough. Across the target -pipeline's platform legs (for a UI test: the Android, iOS, Windows, and macOS/MacCatalyst -legs of `maui-pr-uitests`; for a device test: each device-test platform), require ALL of: -- the target test appears with `outcome == "Passed"` on **every** platform leg whose - results contain it, AND -- it appears with `outcome == "Failed"` (or aborted/errored) on **NO** leg, AND -- **no platform is left unverified.** For each platform family the target pipeline covers, - that platform's leg must have CONCLUDED on `C.headSha`. If a platform leg concluded and - its results simply do not contain the test, the test does not run on that platform — that - is fine, not a gap. But if a platform leg that *would* run the test has **not concluded** - (pending, or an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been - kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet validated - across platforms: record `skipped: target test green on but not yet - verified on (leg(s) pending / need /azp run) on PR #

` and - stop this gate WITHOUT marking ready. - -A target test that never appears on ANY concluded leg (**not executed** anywhere — e.g. its -`/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: +(The prefetch already exposes per-leg status in `C.failedLegs` / the checks context, and +`gh pr checks

` lists the same per-leg rows with platform+category in the name — use +whichever is handy; the build timeline is the authoritative cross-check on the exact build.) + +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, the leg that runs its +category is green on **every platform it runs on** — a fix that repairs one platform must not +silently regress the same test's leg on another, so a green leg on the originally-red platform +alone is NOT enough. Across the target pipeline's platform legs (for a UI test: the Android, +iOS, Windows, and macOS/MacCatalyst legs running the target's category; for a device test: each +device-test platform), require ALL of: +- the target's category leg is `result == "succeeded"` **and** `state == "completed"` on + **every** platform that runs it, AND +- that leg is `failed` / `canceled` / aborted on **NO** platform, AND +- **no platform is left unverified.** For each platform family the target pipeline covers, that + platform's category leg must have CONCLUDED (`state == "completed"`) on `C.headSha`. If a + platform simply has no leg for the target's category, the test does not run there — that is + fine, not a gap. But if a platform's category leg has **not concluded** (`state` is + `inProgress` / pending, or an `/azp`-gated `maui-pr-uitests` / `maui-pr-devicetests` leg that + has not been kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet + validated across platforms: record `skipped: target test green on but + not yet verified on (leg(s) pending / need /azp run) on PR #

` + and stop this gate WITHOUT marking ready. + +A target test whose category leg never concluded on ANY platform (**not executed** anywhere — +e.g. its `/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: target test not yet executed on PR #

( not run — needs /azp run)` and stop -this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in the same group -is not the target test, and a pass on one platform is not a pass on the others. - -**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` - comment for THIS head SHA already exists, the mark-ready already ran for this head — - record `already-marked-ready PR #

(head )` and stop (the already-ready - precondition above handles p/0 label reconciliation for PRs already flipped to ready). +this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg (a different category +on the same platform) is not the target's leg, and a green leg on one platform is not a pass on +the others. + +**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN. The 🎯 comment, +the mark-ready, and the `p/0` label are THREE SEPARATE safe-outputs — the comment +existing does NOT prove the mark-ready took effect, so they are tracked independently: + +- **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach + T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So + if a prior bot `🎯 … target test … validated … on ` comment for THIS head + already exists, the comment landed on an earlier sweep but the **mark-ready did NOT take + effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the + duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the + comment's existence as "already marked ready" while the PR is still a draft. Record this + case as `re-marking PR #

(🎯 present; mark-ready did not take on a prior sweep)`. +- **Atomicity budget pre-check (Hard-Rule 7).** Determine the outputs this gate will emit: + `mark_pull_request_as_ready_for_review` + `add_labels` always, plus `add_comment` unless + `SUPPRESS_COMMENT`. Verify a free per-run slot remains in EACH bucket you are about to + use. If ANY required bucket is exhausted, emit NONE of them — record `skipped: per-run + cap reached; deferring mark-ready PR #

to next cycle` and stop this gate. Never mark a + PR ready (or label it) without also posting its 🎯 audit comment in the same sweep — the + set either all lands or all defers. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. -- Otherwise emit THREE safe-outputs for THIS PR number `

`: - 1. `add_comment`: `🎯 Target test validated green on - passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> - Transitioning this PR from draft to ready for review and adding `p/0`; a maintainer - still reviews and merges.` +- Otherwise emit for THIS PR number `

`: + 1. `add_comment` (ONLY if not `SUPPRESS_COMMENT`): `🎯 Target test validated green on + passed on ALL platforms it runs on (, + buildId ). — not + caused by this fix."> Transitioning this PR from draft to ready for review and adding + `p/0`; a maintainer still reviews and merges.` 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index e899733fe4ec..1eb9aa8faa74 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"d6e79d35df7389a64d6aeb096818db2ba892e8ae8b2bc9646cb9c107a4fe54b4","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"7e6c685cc70a4871c3d9f10712f65acd3c4b3f7319d9afe8a23e8631b81c7959","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 676f3044a9e5..01a54d324b17 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -408,9 +408,13 @@ through `safe-outputs`. edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, - `add_comment` 3, `update_pull_request` 3. Note an ADVANCE spends one push **and** - one update **and** one comment, so ≤ 3 advances/run; surfacing a green or - annotating a flake spends one comment. When a bucket is exhausted, do NOT keep + `add_comment` 3, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` + 3, `add_labels` 3 (counts LABELS, not calls). Note an ADVANCE spends one push + **and** one update **and** one comment, so ≤ 3 advances/run; surfacing a green or + annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** spends one + comment **and** one mark-ready **and** one label as an ALL-OR-NOTHING set (T3 + pre-checks those buckets and defers the whole PR if any is exhausted — never mark + a PR ready without its 🎯 audit comment). When a bucket is exhausted, do NOT keep emitting (extras are silently dropped) — record `skipped: per-run cap reached; deferring PR #

to next cycle` for each remaining PR so the drop is a deliberate, logged decision. The continuous loop picks the deferred PRs up next @@ -741,10 +745,13 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: - **2a — Target-green fast-path (draft `[ci-fix]` PRs only).** If `C.dataComplete == true` AND the Step 3.6 preconditions hold (draft PR, `[ci-fix] ` title prefix AND the `agentic-workflows` label), run Step 3.6 **T1–T2** against `C.headSha` now: identify - the target test(s) and drill the PR's OWN AzDO test-results. If EVERY target test is - **VALIDATED-GREEN** (per T2's all-platform definition below — the target test PASSES - on every platform leg that ran it, `Failed` on none, and no *target* platform leg is - still pending) AND every leg in + the target test(s) and read the PR's OWN build **timeline / per-leg status** (anonymous + `_apis/build` — never `_apis/test`, per Hard-Rule 8). If EVERY target test is + **VALIDATED-GREEN** (per T2's all-platform definition below — the target's category leg + is `succeeded` on every platform that runs it, failed on none, and NO target platform + family the pipeline covers is still pending/unconcluded, per T2's "no platform left + unverified" rule; a platform that simply has no leg for the target's category — the test + doesn't run there — is fine, not a gap) AND every leg in `C.failedLegs` that has ALREADY concluded classifies as **unrelated flake** (Step 4 / Step 4.7 method — the fix is implicated in NO completed red), then the fix is proven regardless of unrelated *pending* legs → run **Step 3.6 T3** (mark ready + 🎯 comment) @@ -767,19 +774,27 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: #

primary CI gate (maui-pr) not green on ; waiting` and stop — do NOT surface. (The `/azp`-gated `maui-pr-uitests` (def 313) / `maui-pr-devicetests` (def 314) legs MAY still be un-run — that is expected and is named below, not a - reason to withhold the surface.) **Idempotency:** scan the PR's existing comments - for a prior bot `✅ … validated … on ` note for THIS head SHA — if one - already exists, record `already-surfaced PR #

(head )` and stop - WITHOUT re-commenting (re-surfacing the same green every tick is noise and burns - the per-run comment budget other PRs need). Otherwise resolve the attempt number from - `C.effectiveAttempt` (the authoritative max(marker, bot-commit) counter; omit the - number only if it is somehow indeterminate). **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `✅` validated-green body to the run log, tally `dry-run: would-surface-green PR #

`, and stop. Otherwise `add_comment` on PR #

: `✅ Attempt /10 validated - — the fix's CI is green on . Ready for human review.` - Name any `/azp`-gated legs (uitests def 313 / devicetests def 314) that have not - run and still need a maintainer `/azp run`. Do NOT advance. Record - `surfaced-green PR #

(attempt /10)`, then run **Step 3.6** - (target-test readiness gate) for this PR before stopping. *(This directly - attacks the real bottleneck — no reviews — so it is the highest-value outcome.)* + reason to withhold the surface.) **Comment idempotency + dry-run suppress the ✅ + comment ONLY — neither skips Step 3.6.** Scan the PR's existing comments for a prior + bot `✅ … validated … on ` note for THIS head SHA; if one exists, set + `SKIP_SURFACE_COMMENT = true`. Resolve the attempt number from `C.effectiveAttempt` + (the authoritative max(marker, bot-commit) counter; omit the number only if it is + somehow indeterminate). Then post the surface comment UNLESS suppressed: + - if `dry_run == "true"`: do NOT emit — print the intended `✅` validated-green body to + the run log and tally `dry-run: would-surface-green PR #

`; + - else if `SKIP_SURFACE_COMMENT`: do NOT re-post — record `already-surfaced PR #

+ (head )` (re-surfacing the same green every tick is noise and burns the + per-run comment budget other PRs need); + - else `add_comment` on PR #

: `✅ Attempt /10 validated — the fix's CI is + green on . Ready for human review.` naming any `/azp`-gated legs (uitests + def 313 / devicetests def 314) that have not run and still need a maintainer `/azp + run`; record `surfaced-green PR #

(attempt /10)`. + Do NOT advance. Then — in ALL of the above cases — run **Step 3.6** (target-test + readiness gate) for this PR before stopping: its `/azp`-gated target legs may conclude + green on this SAME head SHA on a LATER sweep (an `/azp run` adds no commit), and Step + 3.6 is the ONLY place the draft→ready flip happens, so it MUST re-evaluate every sweep — + never `stop` here before it. *(This directly attacks the real bottleneck — no reviews — + so it is the highest-value outcome.)* 4. **Red → classify caused-by-fix vs unrelated-flake.** If `C.overallConclusion == "failure"`, analyze the PR's OWN failing build (NOT `main`): find the AzDO `maui-pr` build for this PR (filter builds by `branchName=refs/pull/

/merge`, @@ -787,19 +802,26 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: method and Step 4.7 flake buckets to `C.failedLegs`. - **Unrelated flake only** (every failed leg is known-flaky / infra / a pre-existing baseline red NOT introduced by the fix): do NOT burn an attempt. - **Idempotency first:** scan the PR's existing comments for a prior bot - `♻️ … unrelated flake … on ` note for THIS head SHA — if one already - exists, record `already-annotated-flake PR #

(head )` and stop - WITHOUT re-commenting (re-annotating the same flake every 12h sweep is noise and - burns the per-run comment budget other PRs need). Otherwise resolve the attempt - number from `C.effectiveAttempt` (the authoritative max(marker, bot-commit) - counter), omitting the `Attempt /10:` prefix only if it is somehow - indeterminate. **Dry-run gate (Step 0):** if `dry_run == "true"`, do NOT emit any comment — instead print the intended `♻️` unrelated-flake body to the run log, tally `dry-run: would-annotate-flake PR #

`, and stop. Otherwise `add_comment` on PR #

: `♻️ Attempt /10: red is - unrelated flake on leg(s) () on ; the fix itself is not - implicated. A maintainer re-run (/azp run ) should clear it.` Record - `annotated-flake PR #

(head )`, then run **Step 3.6** - (target-test readiness gate) for this PR before stopping. *(Round 1: human re-runs; - Round 2: auto re-trigger.)* + **Comment idempotency + dry-run suppress the ♻️ comment ONLY — neither skips Step + 3.6.** Scan the PR's existing comments for a prior bot `♻️ … unrelated flake … on + ` note for THIS head SHA; if one exists, set `SKIP_FLAKE_COMMENT = true`. + Resolve the attempt number from `C.effectiveAttempt` (the authoritative max(marker, + bot-commit) counter), omitting the `Attempt /10:` prefix only if it is + somehow indeterminate. Then post the flake note UNLESS suppressed: + - if `dry_run == "true"`: do NOT emit — print the intended `♻️` unrelated-flake body + to the run log and tally `dry-run: would-annotate-flake PR #

`; + - else if `SKIP_FLAKE_COMMENT`: do NOT re-post — record `already-annotated-flake PR + #

(head )` (re-annotating the same flake every 12h sweep is noise and + burns the per-run comment budget other PRs need); + - else `add_comment` on PR #

: `♻️ Attempt /10: red is unrelated flake on + leg(s) () on ; the fix itself is not implicated. A + maintainer re-run (/azp run ) should clear it.` record `annotated-flake + PR #

(head )`. + Then — in ALL of the above cases — run **Step 3.6** (target-test readiness gate) for + this PR before stopping: its `/azp`-gated target legs may conclude green on this SAME + head SHA on a LATER sweep, and Step 3.6 is the ONLY place the draft→ready flip + happens, so it MUST re-evaluate every sweep — never `stop` here before it. *(Round 1: + human re-runs; Round 2: auto re-trigger.)* - **Caused by the fix** (a failed leg still matches the original target signature, or the fix introduced a NEW failure): advance an attempt. - **Attempt count.** `attempt = C.effectiveAttempt` — the authoritative @@ -838,7 +860,10 @@ not the base branch's flakiness. a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — under `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and record `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR #

`. - Either way, stop this gate. + This reconcile shares the per-run `add_labels` budget (Hard-Rule 7) with T3 mark-ready + transitions, which take priority — if the label bucket is already exhausted, do NOT emit; + record `skipped: p/0 reconcile deferred PR #

(add_labels cap)` (it self-heals next + sweep). Either way, stop this gate. - The PR is unmistakably THIS workflow's own: `[ci-fix] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -855,64 +880,96 @@ test can be identified (e.g. a product build-break rather than a test failure), `skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix is validated by overall-green alone, which the Step 3 branch already handles. -**T2 — Drill into the PR's own build test-results.** Using the SAME build-discovery as -Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` or `sourceVersion == -C.headSha`), find the build(s) on `C.headSha` for the pipeline(s) that actually RUN the -target test — `maui-pr` (def 302) for unit/integration tests, `maui-pr-uitests` (def -313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device tests — then query -the AzDO test-results REST API on `dev.azure.com` for each target test's outcome on that -build: +**T2 — Verify the target test's platform legs are green (anonymous, leg-level).** Per-test +outcomes come from the AzDO **test-results** API (`_apis/test/...`), which is **NOT reachable +anonymously — Hard-Rule 8**: those endpoints 302-redirect to a sign-in page on this runner, so +a `curl` returns an HTML redirect (not JSON) and every target test would look "not executed". +Validate instead at **leg granularity** using ONLY the anonymous `_apis/build/...` timeline +(Hard-Rule 8) — which is a STRONGER bar anyway: a `succeeded` category leg means every test in +that category, including the target, passed on that platform (a de-flaked / target test is +never skipped, so a green category leg cannot hide a target-test failure). + +Map the target test to the CI leg(s) that run it. A leg name encodes platform + test category +(e.g. `Android UITests SafeAreaEdges,Shadow`, `iOS UITests SafeAreaEdges,Shadow`, `macOS +UITests SafeAreaEdges,Shadow`, `Windows UITests SafeAreaEdges,Shadow`). Determine the target +test's UI-test category — its `[Category(UITestCategories.X)]` in the test/HostApp source, +visible in the PR diff or the test file — to know which leg-name substring identifies its legs; +for a device test, the per-platform device-test legs. + +Using the SAME build-discovery as Step 4 (filter AzDO builds by `branchName=refs/pull/

/merge` +or `sourceVersion == C.headSha`), read each build's **timeline** on `C.headSha` for the +pipeline(s) that RUN the target test — `maui-pr` (def 302) for unit/integration tests, +`maui-pr-uitests` (def 313) for Appium UI tests, `maui-pr-devicetests` (def 314) for device +tests: ```bash -ORG=dnceng-public; PROJ=public; P=; BUILD= -# test runs for the build: -curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/runs?buildUri=vstfs:///Build/Build/$BUILD&api-version=7.1" \ - | tee /tmp/gh-aw/agent/testruns_${P}.json | jq -r '.value[] | "\(.id)\t\(.name)"' -# per run id, look for each target test's outcome (repeat per target test). -# IMPORTANT: aggregate outcomes across EVERY platform leg's run (Android/iOS/Windows/ -# macOS) — the test must PASS on all platforms it runs on, not just the one that was red: -curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/test/Runs//results?api-version=7.1&\$top=1000" \ - | jq -r '.value[] | select(.testCaseTitle=="") | "\(.outcome)\t\(.automatedTestName)"' +ORG=dnceng-public; PROJ=public; BUILD= +# Anonymous + Hard-Rule-8-compliant. NEVER call _apis/test/... (it 302-redirects to sign-in). +# Each type=="Job" record is one platform leg: result (succeeded/failed/canceled/null), +# state (completed/inProgress/pending), name (encodes " UITests "): +curl -s "https://dev.azure.com/$ORG/$PROJ/_apis/build/builds/$BUILD/timeline?api-version=7.1" \ + | tee /tmp/gh-aw/agent/timeline_${BUILD}.json \ + | jq -r '.records[] | select(.type=="Job") | "\(.result)\t\(.state)\t\(.name)"' ``` -Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, it PASSES on **every -platform it runs on** — a fix that repairs one platform must not silently regress the same -test on another, so a pass on the originally-red leg alone is NOT enough. Across the target -pipeline's platform legs (for a UI test: the Android, iOS, Windows, and macOS/MacCatalyst -legs of `maui-pr-uitests`; for a device test: each device-test platform), require ALL of: -- the target test appears with `outcome == "Passed"` on **every** platform leg whose - results contain it, AND -- it appears with `outcome == "Failed"` (or aborted/errored) on **NO** leg, AND -- **no platform is left unverified.** For each platform family the target pipeline covers, - that platform's leg must have CONCLUDED on `C.headSha`. If a platform leg concluded and - its results simply do not contain the test, the test does not run on that platform — that - is fine, not a gap. But if a platform leg that *would* run the test has **not concluded** - (pending, or an `/azp`-gated `maui-pr-uitests`/`maui-pr-devicetests` leg that has not been - kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet validated - across platforms: record `skipped: target test green on but not yet - verified on (leg(s) pending / need /azp run) on PR #

` and - stop this gate WITHOUT marking ready. - -A target test that never appears on ANY concluded leg (**not executed** anywhere — e.g. its -`/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: +(The prefetch already exposes per-leg status in `C.failedLegs` / the checks context, and +`gh pr checks

` lists the same per-leg rows with platform+category in the name — use +whichever is handy; the build timeline is the authoritative cross-check on the exact build.) + +Treat a target test as **VALIDATED-GREEN** only if, on `C.headSha`, the leg that runs its +category is green on **every platform it runs on** — a fix that repairs one platform must not +silently regress the same test's leg on another, so a green leg on the originally-red platform +alone is NOT enough. Across the target pipeline's platform legs (for a UI test: the Android, +iOS, Windows, and macOS/MacCatalyst legs running the target's category; for a device test: each +device-test platform), require ALL of: +- the target's category leg is `result == "succeeded"` **and** `state == "completed"` on + **every** platform that runs it, AND +- that leg is `failed` / `canceled` / aborted on **NO** platform, AND +- **no platform is left unverified.** For each platform family the target pipeline covers, that + platform's category leg must have CONCLUDED (`state == "completed"`) on `C.headSha`. If a + platform simply has no leg for the target's category, the test does not run there — that is + fine, not a gap. But if a platform's category leg has **not concluded** (`state` is + `inProgress` / pending, or an `/azp`-gated `maui-pr-uitests` / `maui-pr-devicetests` leg that + has not been kicked), the test's status on that platform is UNKNOWN → the fix is NOT yet + validated across platforms: record `skipped: target test green on but + not yet verified on (leg(s) pending / need /azp run) on PR #

` + and stop this gate WITHOUT marking ready. + +A target test whose category leg never concluded on ANY platform (**not executed** anywhere — +e.g. its `/azp`-gated pipeline has not been kicked) is likewise NOT validated: record `skipped: target test not yet executed on PR #

( not run — needs /azp run)` and stop -this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg in the same group -is not the target test, and a pass on one platform is not a pass on the others. - -**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN: -- **Idempotency:** if a prior bot `🎯 … target test … validated … on ` - comment for THIS head SHA already exists, the mark-ready already ran for this head — - record `already-marked-ready PR #

(head )` and stop (the already-ready - precondition above handles p/0 label reconciliation for PRs already flipped to ready). +this gate WITHOUT marking ready. Do NOT overclaim — a green *sibling* leg (a different category +on the same platform) is not the target's leg, and a green leg on one platform is not a pass on +the others. + +**T3 — Mark ready + report.** If EVERY target test is VALIDATED-GREEN. The 🎯 comment, +the mark-ready, and the `p/0` label are THREE SEPARATE safe-outputs — the comment +existing does NOT prove the mark-ready took effect, so they are tracked independently: + +- **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach + T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So + if a prior bot `🎯 … target test … validated … on ` comment for THIS head + already exists, the comment landed on an earlier sweep but the **mark-ready did NOT take + effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the + duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the + comment's existence as "already marked ready" while the PR is still a draft. Record this + case as `re-marking PR #

(🎯 present; mark-ready did not take on a prior sweep)`. +- **Atomicity budget pre-check (Hard-Rule 7).** Determine the outputs this gate will emit: + `mark_pull_request_as_ready_for_review` + `add_labels` always, plus `add_comment` unless + `SUPPRESS_COMMENT`. Verify a free per-run slot remains in EACH bucket you are about to + use. If ANY required bucket is exhausted, emit NONE of them — record `skipped: per-run + cap reached; deferring mark-ready PR #

to next cycle` and stop this gate. Never mark a + PR ready (or label it) without also posting its 🎯 audit comment in the same sweep — the + set either all lands or all defers. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. -- Otherwise emit THREE safe-outputs for THIS PR number `

`: - 1. `add_comment`: `🎯 Target test validated green on - passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> - Transitioning this PR from draft to ready for review and adding `p/0`; a maintainer - still reviews and merges.` +- Otherwise emit for THIS PR number `

`: + 1. `add_comment` (ONLY if not `SUPPRESS_COMMENT`): `🎯 Target test validated green on + passed on ALL platforms it runs on (, + buildId ). — not + caused by this fix."> Transitioning this PR from draft to ready for review and adding + `p/0`; a maintainer still reviews and merges.` 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into From 32a06ea8ee8d8b26dec2a956638514e82b8bc118 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 12:38:17 -0500 Subject: [PATCH 07/12] ci-fix: address live PR-review comments on Step 3.6 (both twins) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Resolve the three still-live Copilot-reviewer comments on #36461 (each mirrored to both twins). The eight earlier comments about `_apis/test` paging / testCaseTitle-vs-automatedTestName are already obsolete — the prior commit replaced that query with the anonymous `_apis/build/.../timeline` leg-level method — so GitHub marks those threads outdated. A. T1 "no target test" no longer strands build-only fixes as permanent drafts. The old text stopped and claimed "Step 3 handles overall-green", but Step 3 only comments — Step 3.6 is the sole draft->ready flip. Now a build-only fix validates at WHOLE-BUILD granularity: require every maui-pr (def 302) platform build leg succeeded/completed on the head SHA (cross-platform guard applied to the build), set a build-only TARGET, and proceed to T3 to mark ready. T3's comment gains a build-only phrasing variant. B. T2 no longer treats a succeeded category leg as unconditional proof the specific target ran. A job can go green while the target is runtime-skipped (`[Ignore]`, `Assert.Ignore/Inconclusive`, `Skip=`, `#if`-out, early return). Added a diff-based guard: confirm the fix does NOT add any skip/ignore/ short-circuit around the target; if it might, leg-green is insufficient and the PR defers to a human instead of being marked ready. C. Step 3's green-surface ✅ comment no longer overclaims. It said "Ready for human review" even when the PR stays a draft (3.6 may not flip it). Now the "Ready for human review" clause is emitted only when the PR is NOT a draft; a still-draft PR gets a truthful note that the readiness gate decides the flip, and 3.6's 🎯 comment remains the sole ready-for-review announcement. Both locks recompiled 0/0 (body_hash-only delta). Twin symmetry preserved (token-normalized diff unchanged). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 49 +++++++++++++++---- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 49 +++++++++++++++---- 4 files changed, 80 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index c19246d454ef..e0f883690c96 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"1dfa097f616b04e3563d01a0cbee4eaa595acd52c5a5629e1b485976af39670d","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"443edbe1521b53453e7fb263745b72ede309696b2818058cb08ac79f663d6997","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index a9c2bf8a6868..94406ba64ac4 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -796,9 +796,13 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: (head )` (re-surfacing the same green every tick is noise and burns the per-run comment budget other PRs need); - else `add_comment` on PR #

: `✅ Attempt /10 validated — the fix's CI is - green on . Ready for human review.` naming any `/azp`-gated legs (uitests - def 313 / devicetests def 314) that have not run and still need a maintainer `/azp - run`; record `surfaced-green PR #

(attempt /10)`. + green on .` naming any `/azp`-gated legs (uitests def 313 / devicetests def + 314) that have not run and still need a maintainer `/azp run`; record `surfaced-green + PR #

(attempt /10)`. (Do NOT assert "ready for human review" on a PR that + is still a draft — Step 3.6, not this comment, owns the draft→ready flip and posts its + own 🎯 announcement when it fires.) Do NOT advance. Then — in ALL of the above cases — run **Step 3.6** (target-test readiness gate) for this PR before stopping: its `/azp`-gated target legs may conclude green on this SAME head SHA on a LATER sweep (an `/azp run` adds no commit), and Step @@ -886,18 +890,40 @@ not the base branch's flakiness. addresses (and the PR's own diff), extract the fully-qualified test method name(s) the fix targets — e.g. `SafeAreaShouldWorkOnAllShellTabs`. For a de-flake it is the de-flaked test; for a product fix it is the originally-failing test(s). If NO specific -test can be identified (e.g. a product build-break rather than a test failure), record -`skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix -is validated by overall-green alone, which the Step 3 branch already handles. +test can be identified (e.g. a product build-break rather than a test failure), this is a +**build-only fix** — there is no single test to validate cross-platform, so validate at +**whole-build** granularity rather than stopping (Step 3 only *comments*; Step 3.6 is the +sole draft→ready flip, so a build-only fix is undrafted HERE or not at all). We only reach +this gate from Step 3 (green) / Step 4 (unrelated-flake) / gate-2a, so the fix is not +implicated in any concluded red; additionally require, via the T2 timeline method on +`C.headSha`, that the primary build pipeline `maui-pr` (def 302) has CONCLUDED with EVERY +one of its platform build legs `succeeded`/`completed` and NONE failed/canceled or still +pending — the build is green on **every** platform, not just the originally-broken one (the +cross-platform guard, applied to the build instead of a test). If so, set `TARGET := "the +maui-pr build (build-only fix — no single target test)"` and proceed to **T3** to mark +ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR +#

not yet whole-build green (leg(s) pending)` and stop this gate WITHOUT marking +ready (a green subset is not enough — a still-pending build leg could yet fail). **T2 — Verify the target test's platform legs are green (anonymous, leg-level).** Per-test outcomes come from the AzDO **test-results** API (`_apis/test/...`), which is **NOT reachable anonymously — Hard-Rule 8**: those endpoints 302-redirect to a sign-in page on this runner, so a `curl` returns an HTML redirect (not JSON) and every target test would look "not executed". Validate instead at **leg granularity** using ONLY the anonymous `_apis/build/...` timeline -(Hard-Rule 8) — which is a STRONGER bar anyway: a `succeeded` category leg means every test in -that category, including the target, passed on that platform (a de-flaked / target test is -never skipped, so a green category leg cannot hide a target-test failure). +(Hard-Rule 8) — a `succeeded` category leg means every test in that category **that actually +ran** passed on that platform. This is a strong bar **only if the target test genuinely +executes**: a job can go green while one specific test is skipped at runtime (`[Ignore]`, +`Assert.Ignore()`, `Assert.Inconclusive()`, a `Skip=`/conditional `[Fact]`, an `#if`-out, or +an early `return` before the asserts). So before trusting a green leg as proof the target +passed, **confirm from the PR's OWN diff that the fix does NOT skip, ignore, disable, or +short-circuit the target test** (it adds no `[Ignore]`/`[Explicit]`, `Assert.Ignore`/ +`Assert.Inconclusive`, `Skip=`, category-exclusion, `#if`-out, or early `return` around the +target). If the fix could cause the target to be runtime-skipped rather than genuinely pass, +leg-level green is NOT sufficient evidence — record `skipped: target test may be +runtime-skipped by this fix (diff adds ); leg-green insufficient, deferring to human +on PR #

` and stop this gate WITHOUT marking ready. Otherwise (the target genuinely runs +and asserts, as a de-flake or product fix does) a green category leg cannot hide a +target-test failure, so treat it as authoritative. Map the target test to the CI leg(s) that run it. A leg name encodes platform + test category (e.g. `Android UITests SafeAreaEdges,Shadow`, `iOS UITests SafeAreaEdges,Shadow`, `macOS @@ -979,7 +1005,10 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> Transitioning this PR from draft to ready for review and adding - `p/0`; a maintainer still reviews and merges.` + `p/0`; a maintainer still reviews and merges.` (For a **build-only fix** — the T1 + whole-build fallback, no single target test — phrase the first clause as `🎯 Build + validated green on — the maui-pr build passed on ALL platforms (buildId + ).` instead of naming a test.) 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 1eb9aa8faa74..6e5ec34ca057 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"7e6c685cc70a4871c3d9f10712f65acd3c4b3f7319d9afe8a23e8631b81c7959","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"19c9b6566cb7e0814e93b0c0745fb9d17f8c1229b26de3237e8f53aeae6603c2","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 01a54d324b17..ee8ffcbeac8f 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -786,9 +786,13 @@ Run these gates in order — the FIRST that fires decides this cycle's outcome: (head )` (re-surfacing the same green every tick is noise and burns the per-run comment budget other PRs need); - else `add_comment` on PR #

: `✅ Attempt /10 validated — the fix's CI is - green on . Ready for human review.` naming any `/azp`-gated legs (uitests - def 313 / devicetests def 314) that have not run and still need a maintainer `/azp - run`; record `surfaced-green PR #

(attempt /10)`. + green on .` naming any `/azp`-gated legs (uitests def 313 / devicetests def + 314) that have not run and still need a maintainer `/azp run`; record `surfaced-green + PR #

(attempt /10)`. (Do NOT assert "ready for human review" on a PR that + is still a draft — Step 3.6, not this comment, owns the draft→ready flip and posts its + own 🎯 announcement when it fires.) Do NOT advance. Then — in ALL of the above cases — run **Step 3.6** (target-test readiness gate) for this PR before stopping: its `/azp`-gated target legs may conclude green on this SAME head SHA on a LATER sweep (an `/azp run` adds no commit), and Step @@ -876,18 +880,40 @@ not the base branch's flakiness. addresses (and the PR's own diff), extract the fully-qualified test method name(s) the fix targets — e.g. `SafeAreaShouldWorkOnAllShellTabs`. For a de-flake it is the de-flaked test; for a product fix it is the originally-failing test(s). If NO specific -test can be identified (e.g. a product build-break rather than a test failure), record -`skipped: readiness N/A PR #

(no target test)` and stop this gate — a build-only fix -is validated by overall-green alone, which the Step 3 branch already handles. +test can be identified (e.g. a product build-break rather than a test failure), this is a +**build-only fix** — there is no single test to validate cross-platform, so validate at +**whole-build** granularity rather than stopping (Step 3 only *comments*; Step 3.6 is the +sole draft→ready flip, so a build-only fix is undrafted HERE or not at all). We only reach +this gate from Step 3 (green) / Step 4 (unrelated-flake) / gate-2a, so the fix is not +implicated in any concluded red; additionally require, via the T2 timeline method on +`C.headSha`, that the primary build pipeline `maui-pr` (def 302) has CONCLUDED with EVERY +one of its platform build legs `succeeded`/`completed` and NONE failed/canceled or still +pending — the build is green on **every** platform, not just the originally-broken one (the +cross-platform guard, applied to the build instead of a test). If so, set `TARGET := "the +maui-pr build (build-only fix — no single target test)"` and proceed to **T3** to mark +ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR +#

not yet whole-build green (leg(s) pending)` and stop this gate WITHOUT marking +ready (a green subset is not enough — a still-pending build leg could yet fail). **T2 — Verify the target test's platform legs are green (anonymous, leg-level).** Per-test outcomes come from the AzDO **test-results** API (`_apis/test/...`), which is **NOT reachable anonymously — Hard-Rule 8**: those endpoints 302-redirect to a sign-in page on this runner, so a `curl` returns an HTML redirect (not JSON) and every target test would look "not executed". Validate instead at **leg granularity** using ONLY the anonymous `_apis/build/...` timeline -(Hard-Rule 8) — which is a STRONGER bar anyway: a `succeeded` category leg means every test in -that category, including the target, passed on that platform (a de-flaked / target test is -never skipped, so a green category leg cannot hide a target-test failure). +(Hard-Rule 8) — a `succeeded` category leg means every test in that category **that actually +ran** passed on that platform. This is a strong bar **only if the target test genuinely +executes**: a job can go green while one specific test is skipped at runtime (`[Ignore]`, +`Assert.Ignore()`, `Assert.Inconclusive()`, a `Skip=`/conditional `[Fact]`, an `#if`-out, or +an early `return` before the asserts). So before trusting a green leg as proof the target +passed, **confirm from the PR's OWN diff that the fix does NOT skip, ignore, disable, or +short-circuit the target test** (it adds no `[Ignore]`/`[Explicit]`, `Assert.Ignore`/ +`Assert.Inconclusive`, `Skip=`, category-exclusion, `#if`-out, or early `return` around the +target). If the fix could cause the target to be runtime-skipped rather than genuinely pass, +leg-level green is NOT sufficient evidence — record `skipped: target test may be +runtime-skipped by this fix (diff adds ); leg-green insufficient, deferring to human +on PR #

` and stop this gate WITHOUT marking ready. Otherwise (the target genuinely runs +and asserts, as a de-flake or product fix does) a green category leg cannot hide a +target-test failure, so treat it as authoritative. Map the target test to the CI leg(s) that run it. A leg name encodes platform + test category (e.g. `Android UITests SafeAreaEdges,Shadow`, `iOS UITests SafeAreaEdges,Shadow`, `macOS @@ -969,7 +995,10 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ passed on ALL platforms it runs on (, buildId ). — not caused by this fix."> Transitioning this PR from draft to ready for review and adding - `p/0`; a maintainer still reviews and merges.` + `p/0`; a maintainer still reviews and merges.` (For a **build-only fix** — the T1 + whole-build fallback, no single target test — phrase the first clause as `🎯 Build + validated green on — the maui-pr build passed on ALL platforms (buildId + ).` instead of naming a test.) 2. `mark_pull_request_as_ready_for_review` with `reason:` a one-line justification naming the validated test(s) and ``. 3. `add_labels` with `labels: ["p/0"]` for PR #

— put the now-review-ready fix into From 6b3ba3fa6f0da1d4d78547b1c6dcfccaa9c2e080 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:19:36 -0500 Subject: [PATCH 08/12] =?UTF-8?q?ci-fix:=20adversarial-review=20round=20?= =?UTF-8?q?=E2=80=94=20cap=20sizing,=20T3=20build-only=20idempotency,=20PS?= =?UTF-8?q?1=20web-flow=20precision?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies four verified findings from a 3-model adversarial self-review of the Step 3.6 draft→ready capability (both twins + shared prefetch script): 1. add_comment cap 3→6. A green DRAFT PR flipped ready in one sweep spends TWO comment slots (Step 3 ✅ surface, which still names the /azp-gated legs a human must kick, AND Step 3.6 T3 🎯 readiness). At max:3 the shared comment bucket drained after ~1 flip and T3's atomicity pre-check then deferred every further mark-ready while the mark-ready/add_labels buckets (also 3) sat idle. Sizing 6 lets ~3 flips (2 comments each) land per sweep. Hard-Rule 7 caps updated to match. 2. T3 comment-idempotency broadened. The build-only path posts "🎯 Build validated green …" but the prior-comment scan matched only "🎯 … target test … validated …", so a landed build-only comment whose mark-ready failed would be re-posted every sweep. Scan now keys on the common "validated green … on " substring so both phrasings are recognized. 3. PS1 human-committer carve-out narrowed to the exact self-commit signature. Test-AnyHumanCommitActor previously suppressed committer-based hand-off whenever the author was a loop-bot, so a maintainer amending a bot-authored commit (author stays bot, committer becomes the maintainer) was wrongly read as non-human and the hand-off was missed. Now suppress ONLY when committer=='web-flow' AND author is a loop-bot (the API-created initial PR commit). Empirically verified against pulls/N/commits that the loop's initial commit has committer.login=web-flow and author.login=github-actions[bot]. 4. Step 8 outcome line: when a cycle chains surfaced-green → marked-ready, record ONLY the terminal marked-ready line so one-line-per-issue aggregators don't double-count. Both locks recompiled (v0.80.9): add_comment max 3→6 + body_hash only; no action or permission drift. Twin symmetry preserved (token-normalized diff still 140). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Query-CiFixPRs.ps1 | 44 ++++++++++++------- .../workflows/ci-status-fix-net11.lock.yml | 34 +++++++------- .github/workflows/ci-status-fix-net11.md | 37 +++++++++++----- .github/workflows/ci-status-fix.lock.yml | 34 +++++++------- .github/workflows/ci-status-fix.md | 37 +++++++++++----- 5 files changed, 117 insertions(+), 69 deletions(-) diff --git a/.github/scripts/Query-CiFixPRs.ps1 b/.github/scripts/Query-CiFixPRs.ps1 index 54836a4a2003..91c5a161c931 100755 --- a/.github/scripts/Query-CiFixPRs.ps1 +++ b/.github/scripts/Query-CiFixPRs.ps1 @@ -39,11 +39,12 @@ $BotLogins = @( # create_pull_request commit is authored by github-actions[bot] but COMMITTED by # web-flow, because gh-aw builds the PR's initial commit through the GitHub API and # GitHub stamps API-created commits with a web-flow committer. So a web-flow committer - # does NOT by itself prove human engagement — Test-AnyHumanCommitActor only lets a - # web-flow (or any human) committer trip the hand-off when the commit AUTHOR is not one - # of this workflow's own bot identities. push-to-pull-request-branch commits, by - # contrast, are authored AND committed by github-actions[bot] (a real git push), so the - # author check alone already excludes them. + # does NOT by itself prove human engagement — Test-AnyHumanCommitActor suppresses a + # committer-based hand-off ONLY for the exact self-commit signature (committer + # 'web-flow' AND author one of this workflow's own bot identities). A named human who + # commits a bot-authored commit (committer != 'web-flow') still trips the boundary. + # push-to-pull-request-branch commits, by contrast, are authored AND committed by + # github-actions[bot] (a real git push), so the author check alone already excludes them. 'app/github-actions', 'dotnet-maestro[bot]', 'azure-pipelines[bot]', @@ -65,10 +66,13 @@ $BotLogins = @( # Commit-author logins that identify THIS workflow's own pushes. A commit authored by one # of these is either the create_pull_request commit or a push-to-pull-request-branch commit # — never a human action — even when GitHub stamps its COMMITTER as 'web-flow' (which it -# does for the API-created initial PR commit). Test-AnyHumanCommitActor uses this list to -# stop that self-authored commit's web-flow committer from being read as human engagement, -# which would otherwise make every freshly opened [ci-fix] PR look 'human owned' from its -# first commit and be skipped by the watch loop forever. Compared lowercased. +# does for the API-created initial PR commit). Test-AnyHumanCommitActor uses this list, in +# conjunction with a committer == 'web-flow' check, to stop ONLY that self-authored initial +# commit's web-flow committer from being read as human engagement (which would otherwise +# make every freshly opened [ci-fix] PR look 'human owned' from its first commit and be +# skipped by the watch loop forever). A bot-authored commit with a NAMED human committer +# (committer != 'web-flow') is NOT suppressed — that is a genuine maintainer amend/rebase. +# Compared lowercased. $LoopBotCommitAuthors = @( 'github-actions[bot]', 'github-actions', @@ -238,13 +242,23 @@ function Test-AnyHumanCommitActor { } # A human COMMITTER (e.g. 'web-flow' on a web-UI 'Update branch' merge) counts as - # human engagement ONLY when the author is not one of THIS workflow's own bot - # identities. gh-aw's create_pull_request builds the PR's initial commit through the - # GitHub API, which stamps author=github-actions[bot] but committer=web-flow; without - # this carve-out that self-authored commit reads as 'human engaged' and every fresh - # [ci-fix] PR is skipped by the watch loop from its very first commit. + # human engagement — EXCEPT for this workflow's OWN API-created PR commit, whose + # signature is precisely author=one-of-our-bots AND committer='web-flow'. gh-aw's + # create_pull_request builds the PR's initial commit through the GitHub API, which + # stamps author=github-actions[bot] but committer=web-flow (verified: the top-level + # committer.login on pulls/N/commits is literally 'web-flow'); without this carve-out + # that self-authored commit reads as 'human engaged' and every fresh [ci-fix] PR is + # skipped by the watch loop from its very first commit. Suppress ONLY that exact + # signature (committer 'web-flow' + our own bot author). A NAMED human committer of a + # bot-authored commit (e.g. a maintainer who amends/rebases one of our commits) keeps + # committer != 'web-flow', so it STILL correctly trips human engagement — the earlier + # "author not in $LoopBotCommitAuthors" form wrongly suppressed that real hand-off. + # (A push-to-pull-request-branch commit is authored AND committed by our bot, so + # Test-IsHumanLogin on its committer is already false and never reaches here.) $authorKey = if ($null -ne $authorLogin) { $authorLogin.Trim().ToLowerInvariant() } else { '' } - if ((Test-IsHumanLogin -Login $committerLogin) -and ($LoopBotCommitAuthors -notcontains $authorKey)) { + $committerKey = if ($null -ne $committerLogin) { $committerLogin.Trim().ToLowerInvariant() } else { '' } + $isOwnApiCreatedCommit = ($committerKey -eq 'web-flow') -and ($LoopBotCommitAuthors -contains $authorKey) + if ((Test-IsHumanLogin -Login $committerLogin) -and (-not $isOwnApiCreatedCommit)) { return $true } } diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index e0f883690c96..6452492c8b5b 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"8f63c8d501f58d17f7ead14697eac93d718cbd419ecb4cdeaa73842ce5ec5732","body_hash":"443edbe1521b53453e7fb263745b72ede309696b2818058cb08ac79f663d6997","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"dd010c92073a1bc2da1ef5476844be8b15b73a82341c32f13c715c214cfc745f","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -275,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' + cat << 'GH_AW_PROMPT_e96cf9b8ebb827f5_EOF' - GH_AW_PROMPT_af8900fc66cc33d2_EOF + GH_AW_PROMPT_e96cf9b8ebb827f5_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_af8900fc66cc33d2_EOF' + cat << 'GH_AW_PROMPT_e96cf9b8ebb827f5_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_af8900fc66cc33d2_EOF + Tools: add_comment(max:6), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_e96cf9b8ebb827f5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' + cat << 'GH_AW_PROMPT_e96cf9b8ebb827f5_EOF' - GH_AW_PROMPT_af8900fc66cc33d2_EOF + GH_AW_PROMPT_e96cf9b8ebb827f5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' + cat << 'GH_AW_PROMPT_e96cf9b8ebb827f5_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -334,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_af8900fc66cc33d2_EOF + GH_AW_PROMPT_e96cf9b8ebb827f5_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_af8900fc66cc33d2_EOF' + cat << 'GH_AW_PROMPT_e96cf9b8ebb827f5_EOF' {{#runtime-import .github/workflows/ci-status-fix-net11.md}} - GH_AW_PROMPT_af8900fc66cc33d2_EOF + GH_AW_PROMPT_e96cf9b8ebb827f5_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -562,15 +562,15 @@ 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_597f4682f79cc45e_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_597f4682f79cc45e_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_fff73f4cd250bfc7_EOF' + {"add_comment":{"discussions":false,"max":6,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"create_pull_request":{"allowed_base_branches":["net11.0"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"net11.0","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix-net11] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix-net11] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix-net11] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_fff73f4cd250bfc7_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { - "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", + "add_comment": " CONSTRAINTS: Maximum 6 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", "add_labels": " CONSTRAINTS: Maximum 3 label(s) can be added. Only these labels are allowed: [\"p/0\"]. Target: *.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix-net11] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", @@ -1964,7 +1964,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":6,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"net11.0\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"net11.0\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix-net11] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix-net11] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix-net11] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 94406ba64ac4..820172908f97 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -251,8 +251,15 @@ safe-outputs: # PER-RUN total (not per-PR): a sweep may surface several green PRs and/or # annotate several flaky reds in one run. At max:1 all but the first comment # were silently dropped, starving the workflow's #1 value (surfacing green PRs - # for review). Raised to 3 to match the per-run throughput of the other outputs. - max: 3 + # for review). Sized to 6 (not 3) because a single green DRAFT PR that gets + # flipped ready in one sweep spends TWO comment slots — the Step 3 ✅ surface + # comment (which still names the /azp-gated legs a human must kick, so it is NOT + # redundant with 🎯) AND the Step 3.6 T3 🎯 readiness comment. At max:3 the shared + # bucket drained after ~1 draft flip and T3's atomicity pre-check then deferred + # every further mark-ready even while the mark-ready/add_labels buckets (also 3) + # sat idle; 6 lets ~3 draft flips (2 comments each) land per sweep, so the + # mark-ready:3 / add_labels:3 caps are actually reachable. + max: 6 target: "*" # Hard constraint (defense-in-depth): only comment on THIS workflow's own # ci-fix PRs — [ci-fix-net11] title prefix AND agentic-workflows label. Mirrors the @@ -418,13 +425,16 @@ through `safe-outputs`. on, edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, - `add_comment` 3, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` + `add_comment` 6, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` 3, `add_labels` 3 (counts LABELS, not calls). Note an ADVANCE spends one push **and** one update **and** one comment, so ≤ 3 advances/run; surfacing a green or - annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** spends one - comment **and** one mark-ready **and** one label as an ALL-OR-NOTHING set (T3 - pre-checks those buckets and defers the whole PR if any is exhausted — never mark - a PR ready without its 🎯 audit comment). When a bucket is exhausted, do NOT keep + annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** of a + still-draft PR spends TWO comments (the Step 3 ✅ surface **and** the T3 🎯 + readiness note) **and** one mark-ready **and** one label as an ALL-OR-NOTHING set + (T3 pre-checks those buckets and defers the whole PR if any is exhausted — never + mark a PR ready without its 🎯 audit comment). `add_comment` is therefore sized 6 + (not 3) so ~3 draft flips, at 2 comments each, can land in one sweep instead of the + shared comment bucket starving the otherwise-idle mark-ready/add_labels buckets. When a bucket is exhausted, do NOT keep emitting (extras are silently dropped) — record `skipped: per-run cap reached; deferring PR #

to next cycle` for each remaining PR so the drop is a deliberate, logged decision. The continuous loop picks the deferred PRs up next @@ -984,8 +994,11 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ - **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So - if a prior bot `🎯 … target test … validated … on ` comment for THIS head - already exists, the comment landed on an earlier sweep but the **mark-ready did NOT take + if a prior bot `🎯 … validated green … on ` comment for THIS head + already exists (match the common `validated green … on ` substring so BOTH + the `🎯 Target test validated green` and the build-only `🎯 Build validated green` + phrasings are recognized — keying on `target test` would miss the build-only comment + and re-post it every sweep), the comment landed on an earlier sweep but the **mark-ready did NOT take effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the comment's existence as "already marked ready" while the PR is still a draft. Record this @@ -1650,7 +1663,11 @@ Filed by [`ci-status-fix-net11`](https://github.com/dotnet/maui/blob/main/.githu ### Step 8 — Per-issue tally + end-of-run summary -Per issue, append one outcome line to `/tmp/gh-aw/agent/coverage.txt`: +Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the +terminal outcome for the cycle. When one cycle produces a chained pair (a green draft +PR is `surfaced-green` by Step 3 **and then** `marked-ready` by Step 3.6), record ONLY +the terminal `marked-ready` line — it supersedes `surfaced-green`, so an aggregator +keying on one-line-per-issue never double-counts: ``` # net11.0 attempt- diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 6e5ec34ca057..42816a0f5ac7 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0f90d8e9de95ca8cd61894f1d353808df66a6fc208c68b9d8a5f87fdd07195fb","body_hash":"19c9b6566cb7e0814e93b0c0745fb9d17f8c1229b26de3237e8f53aeae6603c2","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"0659133a216e5786af69f3ce705cfe54f08cc52362e2e05b9fc224429b12344a","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md # @@ -275,24 +275,24 @@ jobs: run: | bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh" { - cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' + cat << 'GH_AW_PROMPT_2ac1d0b4083428f8_EOF' - GH_AW_PROMPT_72573af5f11317cd_EOF + GH_AW_PROMPT_2ac1d0b4083428f8_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_72573af5f11317cd_EOF' + cat << 'GH_AW_PROMPT_2ac1d0b4083428f8_EOF' - Tools: add_comment(max:3), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop - GH_AW_PROMPT_72573af5f11317cd_EOF + Tools: add_comment(max:6), create_pull_request(max:3), update_pull_request(max:3), mark_pull_request_as_ready_for_review(max:3), add_labels(max:3), push_to_pull_request_branch(max:3), missing_tool, missing_data, noop + GH_AW_PROMPT_2ac1d0b4083428f8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_create_pull_request.md" cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_push_to_pr_branch.md" - cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' + cat << 'GH_AW_PROMPT_2ac1d0b4083428f8_EOF' - GH_AW_PROMPT_72573af5f11317cd_EOF + GH_AW_PROMPT_2ac1d0b4083428f8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/mcp_cli_tools_prompt.md" - cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' + cat << 'GH_AW_PROMPT_2ac1d0b4083428f8_EOF' The following GitHub context information is available for this workflow: {{#if github.actor}} @@ -334,12 +334,12 @@ jobs: stop immediately and report the limitation rather than spending turns trying to work around it. - GH_AW_PROMPT_72573af5f11317cd_EOF + GH_AW_PROMPT_2ac1d0b4083428f8_EOF cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md" - cat << 'GH_AW_PROMPT_72573af5f11317cd_EOF' + cat << 'GH_AW_PROMPT_2ac1d0b4083428f8_EOF' {{#runtime-import .github/workflows/ci-status-fix.md}} - GH_AW_PROMPT_72573af5f11317cd_EOF + GH_AW_PROMPT_2ac1d0b4083428f8_EOF } > "$GH_AW_PROMPT" - name: Interpolate variables and render templates uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 @@ -556,15 +556,15 @@ 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_e0cb359b55d46650_EOF' - {"add_comment":{"discussions":false,"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} - GH_AW_SAFE_OUTPUTS_CONFIG_e0cb359b55d46650_EOF + cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_0644bf1434ca0071_EOF' + {"add_comment":{"discussions":false,"max":6,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"add_labels":{"allowed":["p/0"],"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"create_pull_request":{"allowed_base_branches":["main"],"allowed_branches":["ci-fix/**"],"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"base_branch":"main","draft":true,"labels":["agentic-workflows"],"max":3,"max_patch_files":100,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"protected_files_policy":"request_review","title_prefix":"[ci-fix] "},"create_report_incomplete_issue":{},"mark_pull_request_as_ready_for_review":{"max":3,"required_labels":["agentic-workflows"],"required_title_prefix":"[ci-fix] ","target":"*"},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"push_to_pull_request_branch":{"allowed_files":["src/Core/**","src/Controls/**","src/Essentials/**","src/BlazorWebView/**","src/TestUtils/**","src/Templates/**","**/PublicAPI.Unshipped.txt"],"if_no_changes":"warn","max":3,"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","AGENTS.md","CLAUDE.md","GEMINI.md"],"required_labels":["agentic-workflows"],"target":"*","title_prefix":"[ci-fix] "},"report_incomplete":{},"update_pull_request":{"allow_body":true,"allow_title":false,"max":3,"target":"*","update_branch":false}} + GH_AW_SAFE_OUTPUTS_CONFIG_0644bf1434ca0071_EOF - name: Generate Safe Outputs Tools env: GH_AW_TOOLS_META_JSON: | { "description_suffixes": { - "add_comment": " CONSTRAINTS: Maximum 3 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", + "add_comment": " CONSTRAINTS: Maximum 6 comment(s) can be added. Target: *. Supports reply_to_id for discussion threading.", "add_labels": " CONSTRAINTS: Maximum 3 label(s) can be added. Only these labels are allowed: [\"p/0\"]. Target: *.", "create_pull_request": " CONSTRAINTS: Maximum 3 pull request(s) can be created. Title will be prefixed with \"[ci-fix] \". Labels [\"agentic-workflows\"] will be automatically added. Only these labels are allowed: [\"agentic-workflows\"]. PRs will be created as drafts.", "mark_pull_request_as_ready_for_review": " CONSTRAINTS: Maximum 3 pull request(s) can be marked as ready for review.", @@ -1951,7 +1951,7 @@ jobs: GH_AW_ALLOWED_DOMAINS: "*.blob.core.windows.net,*.githubusercontent.com,api.business.githubcopilot.com,api.enterprise.githubcopilot.com,api.github.com,api.githubcopilot.com,api.individual.githubcopilot.com,api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,codeload.github.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,dev.azure.com,docs.github.com,github-cloud.githubusercontent.com,github-cloud.s3.amazonaws.com,github.blog,github.com,github.githubassets.com,helix.dot.net,host.docker.internal,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,lfs.github.com,objects.githubusercontent.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,patch-diff.githubusercontent.com,ppa.launchpad.net,raw.githubusercontent.com,registry.npmjs.org,s.symcb.com,s.symcd.com,security.ubuntu.com,telemetry.enterprise.githubcopilot.com,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\":{\"discussions\":false,\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" + GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"discussions\":false,\"max\":6,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"add_labels\":{\"allowed\":[\"p/0\"],\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"create_pull_request\":{\"allowed_base_branches\":[\"main\"],\"allowed_branches\":[\"ci-fix/**\"],\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"base_branch\":\"main\",\"draft\":true,\"labels\":[\"agentic-workflows\"],\"max\":3,\"max_patch_files\":100,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"protected_files_policy\":\"request_review\",\"title_prefix\":\"[ci-fix] \"},\"create_report_incomplete_issue\":{},\"mark_pull_request_as_ready_for_review\":{\"max\":3,\"required_labels\":[\"agentic-workflows\"],\"required_title_prefix\":\"[ci-fix] \",\"target\":\"*\"},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"true\"},\"push_to_pull_request_branch\":{\"allowed_files\":[\"src/Core/**\",\"src/Controls/**\",\"src/Essentials/**\",\"src/BlazorWebView/**\",\"src/TestUtils/**\",\"src/Templates/**\",\"**/PublicAPI.Unshipped.txt\"],\"if_no_changes\":\"warn\",\"max\":3,\"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\",\"AGENTS.md\",\"CLAUDE.md\",\"GEMINI.md\"],\"required_labels\":[\"agentic-workflows\"],\"target\":\"*\",\"title_prefix\":\"[ci-fix] \"},\"report_incomplete\":{},\"update_pull_request\":{\"allow_body\":true,\"allow_title\":false,\"max\":3,\"target\":\"*\",\"update_branch\":false}}" 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index ee8ffcbeac8f..4d8a0219685b 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -241,8 +241,15 @@ safe-outputs: # PER-RUN total (not per-PR): a sweep may surface several green PRs and/or # annotate several flaky reds in one run. At max:1 all but the first comment # were silently dropped, starving the workflow's #1 value (surfacing green PRs - # for review). Raised to 3 to match the per-run throughput of the other outputs. - max: 3 + # for review). Sized to 6 (not 3) because a single green DRAFT PR that gets + # flipped ready in one sweep spends TWO comment slots — the Step 3 ✅ surface + # comment (which still names the /azp-gated legs a human must kick, so it is NOT + # redundant with 🎯) AND the Step 3.6 T3 🎯 readiness comment. At max:3 the shared + # bucket drained after ~1 draft flip and T3's atomicity pre-check then deferred + # every further mark-ready even while the mark-ready/add_labels buckets (also 3) + # sat idle; 6 lets ~3 draft flips (2 comments each) land per sweep, so the + # mark-ready:3 / add_labels:3 caps are actually reachable. + max: 6 target: "*" # Hard constraint (defense-in-depth): only comment on THIS workflow's own # ci-fix PRs — [ci-fix] title prefix AND agentic-workflows label. Mirrors the @@ -408,13 +415,16 @@ through `safe-outputs`. edit, un-draft, or label any PR that lacks both. 7. **Per-run safe-output caps (per RUN, not per PR).** Each output type is capped per run: `create_pull_request` 3, `push_to_pull_request_branch` 3, - `add_comment` 3, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` + `add_comment` 6, `update_pull_request` 3, `mark_pull_request_as_ready_for_review` 3, `add_labels` 3 (counts LABELS, not calls). Note an ADVANCE spends one push **and** one update **and** one comment, so ≤ 3 advances/run; surfacing a green or - annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** spends one - comment **and** one mark-ready **and** one label as an ALL-OR-NOTHING set (T3 - pre-checks those buckets and defers the whole PR if any is exhausted — never mark - a PR ready without its 🎯 audit comment). When a bucket is exhausted, do NOT keep + annotating a flake spends one comment; a **mark-ready (Step 3.6 T3)** of a + still-draft PR spends TWO comments (the Step 3 ✅ surface **and** the T3 🎯 + readiness note) **and** one mark-ready **and** one label as an ALL-OR-NOTHING set + (T3 pre-checks those buckets and defers the whole PR if any is exhausted — never + mark a PR ready without its 🎯 audit comment). `add_comment` is therefore sized 6 + (not 3) so ~3 draft flips, at 2 comments each, can land in one sweep instead of the + shared comment bucket starving the otherwise-idle mark-ready/add_labels buckets. When a bucket is exhausted, do NOT keep emitting (extras are silently dropped) — record `skipped: per-run cap reached; deferring PR #

to next cycle` for each remaining PR so the drop is a deliberate, logged decision. The continuous loop picks the deferred PRs up next @@ -974,8 +984,11 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ - **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So - if a prior bot `🎯 … target test … validated … on ` comment for THIS head - already exists, the comment landed on an earlier sweep but the **mark-ready did NOT take + if a prior bot `🎯 … validated green … on ` comment for THIS head + already exists (match the common `validated green … on ` substring so BOTH + the `🎯 Target test validated green` and the build-only `🎯 Build validated green` + phrasings are recognized — keying on `target test` would miss the build-only comment + and re-post it every sweep), the comment landed on an earlier sweep but the **mark-ready did NOT take effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the comment's existence as "already marked ready" while the PR is still a draft. Record this @@ -1638,7 +1651,11 @@ Filed by [`ci-status-fix`](https://github.com/dotnet/maui/blob/main/.github/work ### Step 8 — Per-issue tally + end-of-run summary -Per issue, append one outcome line to `/tmp/gh-aw/agent/coverage.txt`: +Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the +terminal outcome for the cycle. When one cycle produces a chained pair (a green draft +PR is `surfaced-green` by Step 3 **and then** `marked-ready` by Step 3.6), record ONLY +the terminal `marked-ready` line — it supersedes `surfaced-green`, so an aggregator +keying on one-line-per-issue never double-counts: ``` # main attempt- From 88a84a0c888bc097c7c5d397fd83c6026909bd42 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:35:51 -0500 Subject: [PATCH 09/12] =?UTF-8?q?ci-fix:=20adversarial-review=20round=203?= =?UTF-8?q?=20=E2=80=94=20p/0=20no=20longer=20fights=20human,=20null-actor?= =?UTF-8?q?=20fail-closed,=20idempotency=20anchor,=20build-only=20gated-pi?= =?UTF-8?q?peline=20guard?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Applies four findings from a fresh 3-model adversarial pass on the updated Step 3.6 diff (opus-4.8 / gpt-5.5 / opus-4.6; the third returned NO FINDINGS). All mirrored to both twins + shared prefetch script. 1. p/0 no longer fights a maintainer (opus-4.8 ⚠️). The Step 3.6 precondition re-added `p/0` to an already-ready [ci-fix] PR EVERY sweep when it was missing. The human-engagement guard inspects comments/reviews/commits — NOT label changes — so a maintainer who removed `p/0` to de-prioritize a validated PR (a pure triage action) had it re-added indefinitely, violating the loop's "never override a human" contract. `p/0` is now applied exactly ONCE, atomically with the draft→ready flip (T3); the already-ready branch records `already-ready` and reconciles nothing. Trade-off: a rare transient p/0-drop at flip time is not auto-re-added, but the PR is still ready with its 🎯 audit comment — strictly preferable to steam-rolling a deliberate de-prioritization. 2. Human-engagement guard fails CLOSED on an unidentifiable commit (gpt-5.5 ⚠️). Test-IsHumanLogin(null) is false, so a commit whose author AND committer GitHub could not map to accounts (both null — e.g. a maintainer amending with a git email not linked to GitHub) was invisible to Test-AnyHumanCommitActor and the loop could push over that human's work. The loop's OWN commits always resolve (author github-actions[bot]; committer github-actions[bot] or web-flow), so a fully-unresolvable commit is external: now treated as human engagement. Scoped to BOTH actors unresolvable so it never over-trips the loop's own commits. 3. T3 comment-idempotency anchored on the 🎯 emoji (opus-4.8 💡). The dedup scan now requires the leading `🎯` anchor plus the contiguous `validated green on `, so the match can never drift into a gapped form that would false-positive on the Step 3 ✅ surface comment and suppress the audit 🎯. 4. Build-only fallback defers gated-pipeline origins (gpt-5.5 ⚠️). The build-only path validates `maui-pr` (302) whole-build green, but a [ci-fix] PR whose ORIGINATING failure was in a /azp-gated pipeline (maui-pr-uitests 313 / maui-pr-devicetests 314) would be undrafted on maui-pr-green alone — those pipelines never auto-run on the PR, so maui-pr green is not evidence the gated break is fixed. Now defers such PRs to a human instead of marking ready. Both locks recompiled (v0.80.9): body_hash only (prompt body is runtime-imported; no safe-output/permission/action drift). Twin symmetry improved (normalized diff 140→124 as the p/0 block is now byte-identical across twins). PS1 parses. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Query-CiFixPRs.ps1 | 14 ++++++ .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 49 ++++++++++++------- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 49 ++++++++++++------- 5 files changed, 78 insertions(+), 38 deletions(-) diff --git a/.github/scripts/Query-CiFixPRs.ps1 b/.github/scripts/Query-CiFixPRs.ps1 index 91c5a161c931..89aa5894ea55 100755 --- a/.github/scripts/Query-CiFixPRs.ps1 +++ b/.github/scripts/Query-CiFixPRs.ps1 @@ -261,6 +261,20 @@ function Test-AnyHumanCommitActor { if ((Test-IsHumanLogin -Login $committerLogin) -and (-not $isOwnApiCreatedCommit)) { return $true } + + # Fail closed on a FULLY-unidentified commit. If GitHub could map NEITHER the author + # NOR the committer to an account (both logins null/empty — e.g. a maintainer who + # amended or pushed with a git email not linked to their GitHub account, so the + # pulls/N/commits API returns author=null AND committer=null), we cannot prove it is + # one of the loop's OWN commits, which ALWAYS resolve (author github-actions[bot]; + # committer github-actions[bot] or web-flow — both real accounts). Treat an + # unidentifiable commit as human engagement rather than silently pushing over a + # maintainer's work: the "never override a human" contract must fail safe toward + # hands-off. (Scoped to BOTH actors being unresolvable so it never over-trips on the + # loop's own commits, whose actors are always resolvable.) + if (($authorKey -eq '') -and ($committerKey -eq '')) { + return $true + } } return $false diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 6452492c8b5b..b49c2a1694c3 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"dd010c92073a1bc2da1ef5476844be8b15b73a82341c32f13c715c214cfc745f","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"e2983ea7a0305a0b1c1e2ba2a9ebfda96f7bf4f0b5ce68c0c1024c59bc8ebe46","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 820172908f97..52fb1f867653 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -878,16 +878,18 @@ not the base branch's flakiness. **Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

()` and stop this gate): - `C.isDraft == true` — if the PR is already ready-for-review, the draft→ready - transition is already done; do NOT re-mark. But still reconcile the priority label so - every validated loop PR carries it: if this PR is unmistakably THIS workflow's own - (`[ci-fix-net11] ` title prefix AND the `agentic-workflows` label) and is MISSING `p/0`, - emit a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — - under `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and - record `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR - #

`. This reconcile shares the per-run `add_labels` budget (Hard-Rule 7) with T3 - mark-ready transitions, which take priority — if the label bucket is already exhausted, do - NOT emit; record `skipped: p/0 reconcile deferred PR #

(add_labels cap)` (it self-heals - next sweep). Either way, stop this gate. + transition is already done; do NOT re-mark **and do NOT re-apply `p/0`**. `p/0` is applied + exactly ONCE, atomically with the draft→ready flip (T3 — all-or-nothing with the 🎯 audit + comment + mark-ready), so an already-ready loop PR that is MISSING `p/0` has almost + certainly had it **removed by a maintainer** de-prioritizing the PR — a pure triage action + the human-engagement guard (which inspects comments/reviews/commits, NOT label changes) + cannot see. Re-adding `p/0` every sweep would fight that maintainer indefinitely, violating + the loop's "never override a human" contract. So the loop does NOT reconcile the label: + record `already-ready PR #

` and stop this gate. (Trade-off: on the rare occasion a + transient API error drops `p/0` at flip time *after* the T3 atomic pre-check passed, it is + not auto-re-added — but the PR is still ready-for-review with its 🎯 audit comment, and + re-adding `p/0` is a trivial manual action; that is strictly preferable to steam-rolling a + maintainer's deliberate de-prioritization.) - The PR is unmistakably THIS workflow's own: `[ci-fix-net11] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -909,9 +911,16 @@ implicated in any concluded red; additionally require, via the T2 timeline metho `C.headSha`, that the primary build pipeline `maui-pr` (def 302) has CONCLUDED with EVERY one of its platform build legs `succeeded`/`completed` and NONE failed/canceled or still pending — the build is green on **every** platform, not just the originally-broken one (the -cross-platform guard, applied to the build instead of a test). If so, set `TARGET := "the -maui-pr build (build-only fix — no single target test)"` and proceed to **T3** to mark -ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR +cross-platform guard, applied to the build instead of a test). A build-only fix is undrafted +ONLY on the strength of the auto-running `maui-pr` (def 302) whole-build green, which the +loop CAN observe: if the PR's `[ci-scan]` issue signature or its own diff indicates the +ORIGINATING failure was in a `/azp`-gated pipeline (`maui-pr-uitests` def 313 or +`maui-pr-devicetests` def 314) rather than `maui-pr` (def 302), do NOT undraft on +`maui-pr`-green alone — those pipelines do not auto-run on this PR (GITHUB_TOKEN cannot +trigger them), so a green `maui-pr` build is NOT evidence the gated build break is fixed; +record `skipped: build-only fix PR #

targets gated pipeline () not run — +deferring to human` and stop this gate. Otherwise, set `TARGET := "the maui-pr build +(build-only fix — no single target test)"` and proceed to **T3** to mark ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR #

not yet whole-build green (leg(s) pending)` and stop this gate WITHOUT marking ready (a green subset is not enough — a still-pending build leg could yet fail). @@ -994,11 +1003,15 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ - **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So - if a prior bot `🎯 … validated green … on ` comment for THIS head - already exists (match the common `validated green … on ` substring so BOTH - the `🎯 Target test validated green` and the build-only `🎯 Build validated green` - phrasings are recognized — keying on `target test` would miss the build-only comment - and re-post it every sweep), the comment landed on an earlier sweep but the **mark-ready did NOT take + if a prior bot comment for THIS head that carries the leading `🎯` anchor AND the + contiguous phrase `validated green on ` already exists (BOTH T3 variants — + `🎯 Target test validated green on ` and the build-only `🎯 Build validated green on + ` — contain that exact contiguous phrase, so this recognizes both; keying on + `target test` alone would instead miss the build-only comment and re-post it every sweep. + **Require the `🎯` anchor** so the match can NEVER be loosened to a gapped + `validated…green…on` form that would false-positive on the Step 3 `✅ … validated — the + fix's CI is green on ` surface comment and wrongly suppress the audit 🎯), the comment + landed on an earlier sweep but the **mark-ready did NOT take effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the comment's existence as "already marked ready" while the PR is still a draft. Record this diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 42816a0f5ac7..5f0af13e4f9c 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"0659133a216e5786af69f3ce705cfe54f08cc52362e2e05b9fc224429b12344a","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"90a1f608da5293dc98763e8badafda8ee1fd02ec2514ba9f0c262dc027031282","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 4d8a0219685b..d27f4e35e10f 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -868,16 +868,18 @@ not the base branch's flakiness. **Preconditions** (ALL must hold; otherwise record `skipped: readiness N/A PR #

()` and stop this gate): - `C.isDraft == true` — if the PR is already ready-for-review, the draft→ready - transition is already done; do NOT re-mark. But still reconcile the priority label so - every validated loop PR carries it: if this PR is unmistakably THIS workflow's own - (`[ci-fix] ` title prefix AND the `agentic-workflows` label) and is MISSING `p/0`, emit - a single `add_labels` `["p/0"]` for PR #

(subject to the Step 0 dry-run gate — under - `dry_run == "true"` tally `dry-run: would-label p/0 PR #

` and emit nothing) and record - `reconciled-label p/0 PR #

(already-ready)`; otherwise record `already-ready PR #

`. - This reconcile shares the per-run `add_labels` budget (Hard-Rule 7) with T3 mark-ready - transitions, which take priority — if the label bucket is already exhausted, do NOT emit; - record `skipped: p/0 reconcile deferred PR #

(add_labels cap)` (it self-heals next - sweep). Either way, stop this gate. + transition is already done; do NOT re-mark **and do NOT re-apply `p/0`**. `p/0` is applied + exactly ONCE, atomically with the draft→ready flip (T3 — all-or-nothing with the 🎯 audit + comment + mark-ready), so an already-ready loop PR that is MISSING `p/0` has almost + certainly had it **removed by a maintainer** de-prioritizing the PR — a pure triage action + the human-engagement guard (which inspects comments/reviews/commits, NOT label changes) + cannot see. Re-adding `p/0` every sweep would fight that maintainer indefinitely, violating + the loop's "never override a human" contract. So the loop does NOT reconcile the label: + record `already-ready PR #

` and stop this gate. (Trade-off: on the rare occasion a + transient API error drops `p/0` at flip time *after* the T3 atomic pre-check passed, it is + not auto-re-added — but the PR is still ready-for-review with its 🎯 audit comment, and + re-adding `p/0` is a trivial manual action; that is strictly preferable to steam-rolling a + maintainer's deliberate de-prioritization.) - The PR is unmistakably THIS workflow's own: `[ci-fix] ` title prefix AND the `agentic-workflows` label (mirrors the safe-output lock; the compensating scope control if the v0.80.9 compiler drops the declarative required-*). @@ -899,9 +901,16 @@ implicated in any concluded red; additionally require, via the T2 timeline metho `C.headSha`, that the primary build pipeline `maui-pr` (def 302) has CONCLUDED with EVERY one of its platform build legs `succeeded`/`completed` and NONE failed/canceled or still pending — the build is green on **every** platform, not just the originally-broken one (the -cross-platform guard, applied to the build instead of a test). If so, set `TARGET := "the -maui-pr build (build-only fix — no single target test)"` and proceed to **T3** to mark -ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR +cross-platform guard, applied to the build instead of a test). A build-only fix is undrafted +ONLY on the strength of the auto-running `maui-pr` (def 302) whole-build green, which the +loop CAN observe: if the PR's `[ci-scan]` issue signature or its own diff indicates the +ORIGINATING failure was in a `/azp`-gated pipeline (`maui-pr-uitests` def 313 or +`maui-pr-devicetests` def 314) rather than `maui-pr` (def 302), do NOT undraft on +`maui-pr`-green alone — those pipelines do not auto-run on this PR (GITHUB_TOKEN cannot +trigger them), so a green `maui-pr` build is NOT evidence the gated build break is fixed; +record `skipped: build-only fix PR #

targets gated pipeline () not run — +deferring to human` and stop this gate. Otherwise, set `TARGET := "the maui-pr build +(build-only fix — no single target test)"` and proceed to **T3** to mark ready. If any `maui-pr` build leg is still unconcluded, record `skipped: build-only fix PR #

not yet whole-build green (leg(s) pending)` and stop this gate WITHOUT marking ready (a green subset is not enough — a still-pending build leg could yet fail). @@ -984,11 +993,15 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ - **Comment idempotency (dup-suppress only — never gates the mark-ready).** We only reach T3 while `C.isDraft == true` (the precondition stops an already-ready PR before here). So - if a prior bot `🎯 … validated green … on ` comment for THIS head - already exists (match the common `validated green … on ` substring so BOTH - the `🎯 Target test validated green` and the build-only `🎯 Build validated green` - phrasings are recognized — keying on `target test` would miss the build-only comment - and re-post it every sweep), the comment landed on an earlier sweep but the **mark-ready did NOT take + if a prior bot comment for THIS head that carries the leading `🎯` anchor AND the + contiguous phrase `validated green on ` already exists (BOTH T3 variants — + `🎯 Target test validated green on ` and the build-only `🎯 Build validated green on + ` — contain that exact contiguous phrase, so this recognizes both; keying on + `target test` alone would instead miss the build-only comment and re-post it every sweep. + **Require the `🎯` anchor** so the match can NEVER be loosened to a gapped + `validated…green…on` form that would false-positive on the Step 3 `✅ … validated — the + fix's CI is green on ` surface comment and wrongly suppress the audit 🎯), the comment + landed on an earlier sweep but the **mark-ready did NOT take effect** (the PR is still a draft) — set `SUPPRESS_COMMENT = true` (do not re-post the duplicate 🎯 comment) but STILL complete the mark-ready + label below. Never treat the comment's existence as "already marked ready" while the PR is still a draft. Record this From a777089146af3146826329ce524e6e157508c2b7 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 13:49:29 -0500 Subject: [PATCH 10/12] =?UTF-8?q?ci-fix:=20adversarial-review=20round=204?= =?UTF-8?q?=20=E2=80=94=20widen=20human-engagement=20fail-closed=20to=20ei?= =?UTF-8?q?ther-null=20actor;=20de-dup=20post-flip=20coverage=20tally?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two findings from a fresh 3-model adversarial pass on 88a84a0c88 (opus-4.8 verified all four round-3 fixes SOUND + found #2 below; gpt-5.5 PS1-guard pass found #1; second gpt-5.5 pass NO FINDINGS). Both are should-fix, both fail in the safe direction. Mirrored to both twins + shared prefetch script. 1. Human-engagement guard now fails CLOSED on EITHER unresolvable commit actor, not only BOTH (Query-CiFixPRs.ps1, Test-AnyHumanCommitActor). Round 3 closed the both-null gap but left the partial-unmapped case open: a maintainer who runs `git commit --amend` on the bot's commit PRESERVES author=github-actions[bot] but stamps the committer as their own git identity — and if that email is not linked to GitHub, committer.login is null. That commit (author resolved to the bot, committer null) fell through as non-human, so the loop could push over a real human hand-off. Widened `($authorKey -eq '') -and (...)` to `-or`. Provably safe against the loop's own commits: BOTH loop signatures resolve BOTH actors (create-PR = github-actions[bot] + web-flow; push = github-actions[bot] twice), so an either-unresolvable commit is never one of ours and the test never over-trips (never stalls a fresh [ci-fix] PR on its own commit). 2. Step 8 coverage tally no longer double-counts a flipped-ready PR in steady state (ci-status-fix.md). The round-3 flow runs Step 3.6 in ALL cases before stopping, so on every post-flip sweep a still-green ready PR records Step 3's `already-surfaced` AND Step 3.6's `already-ready` — two lines for one issue in one cycle. The existing supersede rule only collapsed the flip-cycle pair (`surfaced-green` → `marked-ready`). Generalized it to also collapse the post-flip steady-state pair (`already-surfaced` → `already-ready`): record ONLY the terminal Step 3.6 readiness line. Added `already-surfaced` and `already-ready` to the Step 8 outcome vocabulary (the latter was absent, so an aggregator could not recognize it as terminal). Artifact-only fix — both lines were already idempotent no-ops; no behavioral change. Both locks recompiled (v0.80.9): body_hash only (prompt body runtime-imported; PS1 invoked by path, not embedded — no lock content change). Twin normalized diff holds at 124 (new passages are token-free, byte-identical across twins). PS1 parses. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/scripts/Query-CiFixPRs.ps1 | 26 +++++++++++-------- .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 18 +++++++++---- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 18 +++++++++---- 5 files changed, 43 insertions(+), 23 deletions(-) diff --git a/.github/scripts/Query-CiFixPRs.ps1 b/.github/scripts/Query-CiFixPRs.ps1 index 89aa5894ea55..ac365ff9873c 100755 --- a/.github/scripts/Query-CiFixPRs.ps1 +++ b/.github/scripts/Query-CiFixPRs.ps1 @@ -262,17 +262,21 @@ function Test-AnyHumanCommitActor { return $true } - # Fail closed on a FULLY-unidentified commit. If GitHub could map NEITHER the author - # NOR the committer to an account (both logins null/empty — e.g. a maintainer who - # amended or pushed with a git email not linked to their GitHub account, so the - # pulls/N/commits API returns author=null AND committer=null), we cannot prove it is - # one of the loop's OWN commits, which ALWAYS resolve (author github-actions[bot]; - # committer github-actions[bot] or web-flow — both real accounts). Treat an - # unidentifiable commit as human engagement rather than silently pushing over a - # maintainer's work: the "never override a human" contract must fail safe toward - # hands-off. (Scoped to BOTH actors being unresolvable so it never over-trips on the - # loop's own commits, whose actors are always resolvable.) - if (($authorKey -eq '') -and ($committerKey -eq '')) { + # Fail closed on any commit with an UNIDENTIFIED actor. If GitHub could not map the + # author OR the committer to an account (its login is null/empty — e.g. a maintainer + # who amended or pushed with a git email not linked to their GitHub account, so the + # pulls/N/commits API returns null for that actor), we cannot prove the commit is one + # of the loop's OWN commits. Every loop commit resolves BOTH actors to real accounts + # (create-PR: author github-actions[bot] + committer web-flow; push-to-branch: both + # github-actions[bot]), so an EITHER-unresolvable commit is never one of ours — it is + # external work. The load-bearing case: a maintainer runs `git commit --amend` on the + # bot's commit, which PRESERVES author=github-actions[bot] but stamps the committer as + # their unlinked git email → committer.login null. That partial-unmapped commit (a real + # human hand-off) would otherwise read as non-human and the loop would push over it. + # Treat it as human engagement: the "never override a human" contract must fail safe + # toward hands-off. (Because both loop signatures resolve BOTH actors, this + # either-unresolvable test never over-trips on the loop's own commits.) + if (($authorKey -eq '') -or ($committerKey -eq '')) { return $true } } diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index b49c2a1694c3..4ff15066d7fa 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"e2983ea7a0305a0b1c1e2ba2a9ebfda96f7bf4f0b5ce68c0c1024c59bc8ebe46","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"08cd6cc2ebf6d55c2df807c7192fd0d6ce1f341510fd2c996e3c38c95f32c8fb","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 52fb1f867653..42f95980105d 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -1677,10 +1677,14 @@ Filed by [`ci-status-fix-net11`](https://github.com/dotnet/maui/blob/main/.githu ### Step 8 — Per-issue tally + end-of-run summary Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the -terminal outcome for the cycle. When one cycle produces a chained pair (a green draft -PR is `surfaced-green` by Step 3 **and then** `marked-ready` by Step 3.6), record ONLY -the terminal `marked-ready` line — it supersedes `surfaced-green`, so an aggregator -keying on one-line-per-issue never double-counts: +terminal outcome for the cycle. When one cycle produces a chained pair — a green PR +gets a Step 3 green line (`surfaced-green` on the first comment, or `already-surfaced` +when the ✅ already exists) **and then** a Step 3.6 readiness line (`marked-ready` on the +draft→ready flip, or `already-ready` on a later steady-state sweep of an already-ready +PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes the Step 3 green +line, so an aggregator keying on one-line-per-issue never double-counts. This holds for +BOTH the flip cycle (`surfaced-green` → `marked-ready`) and the post-flip steady state +(`already-surfaced` → `already-ready`): ``` # net11.0 attempt- @@ -1693,7 +1697,11 @@ existing PR), `surfaced-green PR #

` (fix's own CI went green; commented for review, did not advance), `annotated-flake PR #

` (red was unrelated flake; commented, attempt NOT burned), `marked-ready PR #

` (the specific fixed test was confirmed green in the PR's own CI; draft flipped to ready for review), -`waiting PR #

` (CI not settled yet), +`already-surfaced PR #

` (the fix's ✅ green comment already existed this sweep; +re-post suppressed — superseded by the Step 3.6 readiness line when the PR also flips +ready that cycle), `already-ready PR #

` (terminal steady state — the PR was flipped +ready on a prior cycle and remains green on an unchanged head; no action taken, +supersedes `already-surfaced`), `waiting PR #

` (CI not settled yet), `dry-run: would-`, `skipped: `. (The `needs-human-PR` outcome is reserved for the deferred hand-off — Step 6 currently records a skip instead, so it is not emitted.) diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 5f0af13e4f9c..9ff30c1ad1c3 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"90a1f608da5293dc98763e8badafda8ee1fd02ec2514ba9f0c262dc027031282","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"a451d9f511adfa2a08a53544930458e4525f123ccb838af9e7b33b930029d6a0","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index d27f4e35e10f..d46c405f7096 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -1665,10 +1665,14 @@ Filed by [`ci-status-fix`](https://github.com/dotnet/maui/blob/main/.github/work ### Step 8 — Per-issue tally + end-of-run summary Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the -terminal outcome for the cycle. When one cycle produces a chained pair (a green draft -PR is `surfaced-green` by Step 3 **and then** `marked-ready` by Step 3.6), record ONLY -the terminal `marked-ready` line — it supersedes `surfaced-green`, so an aggregator -keying on one-line-per-issue never double-counts: +terminal outcome for the cycle. When one cycle produces a chained pair — a green PR +gets a Step 3 green line (`surfaced-green` on the first comment, or `already-surfaced` +when the ✅ already exists) **and then** a Step 3.6 readiness line (`marked-ready` on the +draft→ready flip, or `already-ready` on a later steady-state sweep of an already-ready +PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes the Step 3 green +line, so an aggregator keying on one-line-per-issue never double-counts. This holds for +BOTH the flip cycle (`surfaced-green` → `marked-ready`) and the post-flip steady state +(`already-surfaced` → `already-ready`): ``` # main attempt- @@ -1681,7 +1685,11 @@ existing PR), `surfaced-green PR #

` (fix's own CI went green; commented for review, did not advance), `annotated-flake PR #

` (red was unrelated flake; commented, attempt NOT burned), `marked-ready PR #

` (the specific fixed test was confirmed green in the PR's own CI; draft flipped to ready for review), -`waiting PR #

` (CI not settled yet), +`already-surfaced PR #

` (the fix's ✅ green comment already existed this sweep; +re-post suppressed — superseded by the Step 3.6 readiness line when the PR also flips +ready that cycle), `already-ready PR #

` (terminal steady state — the PR was flipped +ready on a prior cycle and remains green on an unchanged head; no action taken, +supersedes `already-surfaced`), `waiting PR #

` (CI not settled yet), `dry-run: would-`, `skipped: `. (The `needs-human-PR` outcome is reserved for the deferred hand-off — Step 6 currently records a skip instead, so it is not emitted.) From 705805f98f4e7ce25db559a201441a968114a5bf Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 14:00:46 -0500 Subject: [PATCH 11/12] =?UTF-8?q?ci-fix:=20adversarial-review=20round=205?= =?UTF-8?q?=20=E2=80=94=20align=20Hard-Rule=205=20+=20Step=208=20supersede?= =?UTF-8?q?=20with=20Step=203.6=20terminal=20outcomes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two outcome-consistency findings from a fresh 3-model pass on a777089146 (opus-4.8 + opus-4.6 verified BOTH round-4 fixes sound and the full A–F multi-sweep lifecycle correct; the two findings below are documentation/tally consistency only — no behavioral change). Mirrored to both twins. 1. Hard-Rule 5 "one issue = one outcome" list now enumerates the Step 3.6 terminal outcomes (gpt-5.5 ⚠️). The canonical list previously stopped at "surface a validated-green PR for review" and never mentioned marking the validated draft ready — the highest-value terminal state this PR introduces. Added "mark a target-validated draft PR ready-for-review (Step 3.6 T3 — the terminal outcome that supersedes the same run's surface/annotate precursor line), or record its `already-ready` steady-state no-op". Keeps the rule consistent with the Step 3.6 precondition, the Step 8 vocabulary, and the decision table. 2. Step 8 tally supersede now covers the flake-coincident flip (opus-4.8 💡). The round-4 supersede clause only collapsed a Step 3 GREEN precursor (`surfaced-green`/`already-surfaced`) into the terminal readiness line, but a PR that is unrelated-flake-red AND target-green in the same cycle posts a Step 4 `annotated-flake` line and THEN a Step 3.6 `marked-ready` line — two lines for one issue. Generalized the rule: the readiness line supersedes ANY same-cycle non-readiness precursor (green line OR `annotated-flake`), and the superseded precursor's signal survives in the PR's 🎯/♻️ comment so no information is lost. Artifact/tally-only (pre-existing reachability; both lines were idempotent no-ops). Both locks recompiled (v0.80.9): body_hash only. Twin normalized diff holds at 124 (both passages token-free, byte-identical across twins). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 23 ++++++++++++------- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 23 ++++++++++++------- 4 files changed, 32 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 4ff15066d7fa..da25b0753c61 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"08cd6cc2ebf6d55c2df807c7192fd0d6ce1f341510fd2c996e3c38c95f32c8fb","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"2ec9a9ab2c64d465854662057576b9ffaaed03f6f6fc933d2d3bc6b82d78dec1","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index 42f95980105d..c91783bc9725 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -396,7 +396,10 @@ through `safe-outputs`. 5. **One issue = one outcome per run.** Exactly one of: respond to a maintainer's change-request on the open PR (Track C, Step 3.5.R); open the first fix/help/ de-flake PR; advance an existing PR by one attempt (push a follow-up fix); - surface a validated-green PR for review; annotate an unrelated-flake red; wait + surface a validated-green PR for review; mark a target-validated draft PR + ready-for-review (Step 3.6 T3 — the terminal outcome that supersedes the same + run's surface/annotate precursor line), or record its `already-ready` + steady-state no-op; annotate an unrelated-flake red; wait (CI not yet settled); or a recorded skip (the dedicated needs-human PR is deferred — the attempt cap records a skip instead; see Step 6). Always prefer advancing or opening a PR over a skip when a non-mute diff is producible. @@ -1677,14 +1680,18 @@ Filed by [`ci-status-fix-net11`](https://github.com/dotnet/maui/blob/main/.githu ### Step 8 — Per-issue tally + end-of-run summary Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the -terminal outcome for the cycle. When one cycle produces a chained pair — a green PR -gets a Step 3 green line (`surfaced-green` on the first comment, or `already-surfaced` -when the ✅ already exists) **and then** a Step 3.6 readiness line (`marked-ready` on the +terminal outcome for the cycle. When one cycle produces a chained pair — a PR gets a +same-cycle precursor line and **then** a Step 3.6 readiness line (`marked-ready` on the draft→ready flip, or `already-ready` on a later steady-state sweep of an already-ready -PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes the Step 3 green -line, so an aggregator keying on one-line-per-issue never double-counts. This holds for -BOTH the flip cycle (`surfaced-green` → `marked-ready`) and the post-flip steady state -(`already-surfaced` → `already-ready`): +PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes ANY same-cycle +non-readiness precursor for that PR, so an aggregator keying on one-line-per-issue never +double-counts. The precursor may be a Step 3 green line (`surfaced-green` on the first ✅, +or `already-surfaced` when it already exists) OR — when an unrelated-flake red and a +target-green coincide — a Step 4 `annotated-flake` line; either way the readiness line is +terminal, and the superseded precursor's signal survives in the PR's 🎯/♻️ comment so no +information is lost. This covers the flip cycle (`surfaced-green` → `marked-ready`), the +post-flip steady state (`already-surfaced` → `already-ready`), and the flake-coincident +flip (`annotated-flake` → `marked-ready`): ``` # net11.0 attempt- diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 9ff30c1ad1c3..7c1ca1e1a474 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"a451d9f511adfa2a08a53544930458e4525f123ccb838af9e7b33b930029d6a0","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"67416f7bd3d312a379f302f9b4eb38e2a71e5e0a01767e96ffe0fb0fe172c63d","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index d46c405f7096..1bf4e1891b7a 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -386,7 +386,10 @@ through `safe-outputs`. 5. **One issue = one outcome per run.** Exactly one of: respond to a maintainer's change-request on the open PR (Track C, Step 3.5.R); open the first fix/help/ de-flake PR; advance an existing PR by one attempt (push a follow-up fix); - surface a validated-green PR for review; annotate an unrelated-flake red; wait + surface a validated-green PR for review; mark a target-validated draft PR + ready-for-review (Step 3.6 T3 — the terminal outcome that supersedes the same + run's surface/annotate precursor line), or record its `already-ready` + steady-state no-op; annotate an unrelated-flake red; wait (CI not yet settled); or a recorded skip (the dedicated needs-human PR is deferred — the attempt cap records a skip instead; see Step 6). Always prefer advancing or opening a PR over a skip when a non-mute diff is producible. @@ -1665,14 +1668,18 @@ Filed by [`ci-status-fix`](https://github.com/dotnet/maui/blob/main/.github/work ### Step 8 — Per-issue tally + end-of-run summary Per issue, append **one** outcome line to `/tmp/gh-aw/agent/coverage.txt` — the -terminal outcome for the cycle. When one cycle produces a chained pair — a green PR -gets a Step 3 green line (`surfaced-green` on the first comment, or `already-surfaced` -when the ✅ already exists) **and then** a Step 3.6 readiness line (`marked-ready` on the +terminal outcome for the cycle. When one cycle produces a chained pair — a PR gets a +same-cycle precursor line and **then** a Step 3.6 readiness line (`marked-ready` on the draft→ready flip, or `already-ready` on a later steady-state sweep of an already-ready -PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes the Step 3 green -line, so an aggregator keying on one-line-per-issue never double-counts. This holds for -BOTH the flip cycle (`surfaced-green` → `marked-ready`) and the post-flip steady state -(`already-surfaced` → `already-ready`): +PR) — record ONLY the terminal Step 3.6 readiness line: it supersedes ANY same-cycle +non-readiness precursor for that PR, so an aggregator keying on one-line-per-issue never +double-counts. The precursor may be a Step 3 green line (`surfaced-green` on the first ✅, +or `already-surfaced` when it already exists) OR — when an unrelated-flake red and a +target-green coincide — a Step 4 `annotated-flake` line; either way the readiness line is +terminal, and the superseded precursor's signal survives in the PR's 🎯/♻️ comment so no +information is lost. This covers the flip cycle (`surfaced-green` → `marked-ready`), the +post-flip steady state (`already-surfaced` → `already-ready`), and the flake-coincident +flip (`annotated-flake` → `marked-ready`): ``` # main attempt- From dbb7370ac32949a9175d61d5cac03d9833b1e052 Mon Sep 17 00:00:00 2001 From: PureWeen <223556219+Copilot@users.noreply.github.com> Date: Thu, 9 Jul 2026 15:30:52 -0500 Subject: [PATCH 12/12] =?UTF-8?q?ci-fix:=20address=20Copilot=20review=20?= =?UTF-8?q?=E2=80=94=20T3=20atomicity/SUPPRESS=5FCOMMENT=20consistency=20+?= =?UTF-8?q?=20pin=20version=20ref=20to=20v0.80.9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two doc-accuracy fixes flagged by the Copilot reviewer on PR #36461 (both twins; locks recompiled, metadata-only delta — no config change): 1. T3 atomicity vs idempotency contradiction. The atomicity rule said "never mark a PR ready without also posting its 🎯 audit comment in the same sweep", which directly contradicts the SUPPRESS_COMMENT re-marking path (🎯 already present for this head SHA from a prior sweep, mark-ready did not take → re-mark + label WITHOUT re-posting). Reworded the invariant to "the 🎯 audit comment must be GUARANTEED to exist for this exact head SHA — posted this sweep OR already present from a prior sweep", so the audit trail is never absent yet is not needlessly re-posted. 2. Stale gh-aw version reference. Two passages cited v0.79.8 for the "compiler silently drops required-* for update_pull_request" behavior while the workflow is pinned/compiled with v0.80.9. Re-verified against the v0.80.9 lock: update_pull_request still carries NO required_title_prefix/required_labels (mark-ready + add_labels DO), so the claim holds — only the version label was stale. Bumped to v0.80.9; all version refs now consistent. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/ci-status-fix-net11.lock.yml | 2 +- .github/workflows/ci-status-fix-net11.md | 10 ++++++---- .github/workflows/ci-status-fix.lock.yml | 2 +- .github/workflows/ci-status-fix.md | 10 ++++++---- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index da25b0753c61..8d91aeb34acb 100644 --- a/.github/workflows/ci-status-fix-net11.lock.yml +++ b/.github/workflows/ci-status-fix-net11.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"1d1e00ad6ac9d04eb383e81f3debee9c324ed5cafc81d753cd84e0f1cb0ee645","body_hash":"2ec9a9ab2c64d465854662057576b9ffaaed03f6f6fc933d2d3bc6b82d78dec1","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"96803d5ed69c6add43b9de0074984f2a2b934dc0d187013ae387fb01e537ea74","body_hash":"2cd137cd0021cec08a52c15625dd0e456f7da856bcf0834d68a224b20723ba65","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix-net11.md b/.github/workflows/ci-status-fix-net11.md index c91783bc9725..e397fcafcd26 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -280,7 +280,7 @@ safe-outputs: # never the title, so disable title rewrites — this compiles to allow_title:false # and removes any ability to retitle an arbitrary PR. title: false - # NOTE: gh-aw v0.79.8 does NOT emit required-title-prefix/required-labels into + # NOTE: gh-aw v0.80.9 (the pinned compiler) does NOT emit required-title-prefix/required-labels into # the compiled config for update-pull-request (verified against the lock — it # silently drops them, unlike add-comment / push-to-pull-request-branch which # honor them). So which-PR scoping here relies on prompt Hard-Rule 6 + @@ -420,7 +420,7 @@ through `safe-outputs`. `push_to_pull_request_branch`), and `add_labels` additionally has an `allowed: [p/0]` allowlist so it can ONLY ever add `p/0` — so these can only ever land on THIS workflow's own PRs. `update_pull_request` CANNOT be - config-locked to a title/label in gh-aw v0.79.8 (the compiler silently drops + config-locked to a title/label in gh-aw v0.80.9 (the compiler silently drops `required-*` for that output — verified against the lock), so it keeps `title: false` (no retitles; body-marker edits only) plus this prompt-level guard. Before emitting ANY of these, VERIFY the target PR carries BOTH the @@ -1024,8 +1024,10 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ `SUPPRESS_COMMENT`. Verify a free per-run slot remains in EACH bucket you are about to use. If ANY required bucket is exhausted, emit NONE of them — record `skipped: per-run cap reached; deferring mark-ready PR #

to next cycle` and stop this gate. Never mark a - PR ready (or label it) without also posting its 🎯 audit comment in the same sweep — the - set either all lands or all defers. + PR ready (or label it) unless its 🎯 audit comment is GUARANTEED to exist for this exact + head SHA — either posted in this same sweep, or (in the `SUPPRESS_COMMENT` re-marking case) + already present from a prior sweep. The outputs you DO emit either all land or all defer + together; the audit trail must never be absent, but it is NOT re-posted when it already exists. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop. diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 7c1ca1e1a474..65511f2b3259 100644 --- a/.github/workflows/ci-status-fix.lock.yml +++ b/.github/workflows/ci-status-fix.lock.yml @@ -1,4 +1,4 @@ -# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"5ca0f6b0e94d492930be7a828f80b1a487b436e66d356dcb60c6b702bfab746a","body_hash":"67416f7bd3d312a379f302f9b4eb38e2a71e5e0a01767e96ffe0fb0fe172c63d","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"b0ebf8a2f179900cfe3638e994b27a43cec52bdbdd2331dc1bd4d65762fa2d6b","body_hash":"1825e2b1f7c7bd88241bf37580655489360f9bebc806edd00837a52ce4ad83a0","compiler_version":"v0.80.9","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.63"}} # gh-aw-manifest: {"version":1,"secrets":["COPILOT_PAT_0","COPILOT_PAT_1","COPILOT_PAT_2","COPILOT_PAT_3","COPILOT_PAT_4","COPILOT_PAT_5","COPILOT_PAT_6","COPILOT_PAT_7","COPILOT_PAT_8","COPILOT_PAT_9","GH_AW_CI_TRIGGER_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"34e114876b0b11c390a56381ad16ebd13914f8d5","version":"v4"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e","version":"v6.4.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"8c7d04ebf1ece56cd381446125da3e0f6896294a","version":"v0.80.9"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7","digest":"sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.7@sha256:aae231e4635c8999d039c132f1602d3df850fe9b84a00aa2b5ac981179b5661c"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7","digest":"sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.7@sha256:009caf2e3d88fa77b64e9a03a95a228fc58db0f1701c6d324b29ba5a3c7c79b6"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7","digest":"sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.7@sha256:deb1d4e19de62d51cee0508057a596a19315c3423ada4d675cad136dc8037c96"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.3.27","digest":"sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.3.27@sha256:fe984bddde4ec05d756d9043edb0a32912e6b7b72f6a121b1082f29221421cc7"},{"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.4.0","digest":"sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036","pinned_image":"ghcr.io/github/github-mcp-server:v1.4.0@sha256:2afb26356481d1a350e14544a6e160f7f7ec1561a1ea309b823665abf0309036"}]} # This file was automatically generated by gh-aw (v0.80.9). 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/ci-status-fix.md b/.github/workflows/ci-status-fix.md index 1bf4e1891b7a..9c2f46054029 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -270,7 +270,7 @@ safe-outputs: # never the title, so disable title rewrites — this compiles to allow_title:false # and removes any ability to retitle an arbitrary PR. title: false - # NOTE: gh-aw v0.79.8 does NOT emit required-title-prefix/required-labels into + # NOTE: gh-aw v0.80.9 (the pinned compiler) does NOT emit required-title-prefix/required-labels into # the compiled config for update-pull-request (verified against the lock — it # silently drops them, unlike add-comment / push-to-pull-request-branch which # honor them). So which-PR scoping here relies on prompt Hard-Rule 6 + @@ -410,7 +410,7 @@ through `safe-outputs`. `push_to_pull_request_branch`), and `add_labels` additionally has an `allowed: [p/0]` allowlist so it can ONLY ever add `p/0` — so these can only ever land on THIS workflow's own PRs. `update_pull_request` CANNOT be - config-locked to a title/label in gh-aw v0.79.8 (the compiler silently drops + config-locked to a title/label in gh-aw v0.80.9 (the compiler silently drops `required-*` for that output — verified against the lock), so it keeps `title: false` (no retitles; body-marker edits only) plus this prompt-level guard. Before emitting ANY of these, VERIFY the target PR carries BOTH the @@ -1014,8 +1014,10 @@ existing does NOT prove the mark-ready took effect, so they are tracked independ `SUPPRESS_COMMENT`. Verify a free per-run slot remains in EACH bucket you are about to use. If ANY required bucket is exhausted, emit NONE of them — record `skipped: per-run cap reached; deferring mark-ready PR #

to next cycle` and stop this gate. Never mark a - PR ready (or label it) without also posting its 🎯 audit comment in the same sweep — the - set either all lands or all defers. + PR ready (or label it) unless its 🎯 audit comment is GUARANTEED to exist for this exact + head SHA — either posted in this same sweep, or (in the `SUPPRESS_COMMENT` re-marking case) + already present from a prior sweep. The outputs you DO emit either all land or all defer + together; the audit trail must never be absent, but it is NOT re-posted when it already exists. - **Dry-run gate (Step 0):** if `dry_run == "true"`, emit NOTHING — print the intended readiness comment and "would mark ready + add p/0" to the run log, tally `dry-run: would-mark-ready PR #

`, and stop.