diff --git a/.github/skills/ci-fix/SKILL.md b/.github/skills/ci-fix/SKILL.md new file mode 100644 index 000000000000..d1d94a3bb1c7 --- /dev/null +++ b/.github/skills/ci-fix/SKILL.md @@ -0,0 +1,70 @@ +--- +name: ci-fix +description: Common safety and triage protocol for .NET MAUI CI-fixer workflows. Use whenever investigating, creating, or advancing a `[ci-fix]` or `[ci-fix-net11]` pull request from a `ci-scan` issue, including manual single-issue dispatches and scheduled sweeps. +--- + +# CI-fix triage protocol + +Use this protocol before proposing a code change or emitting a CI-fixer safe +output. The calling workflow supplies its branch, labels, title prefix, attempt +limit, and allowed write surface; preserve those caller-specific restrictions. + +## Return a decision + +For each candidate, state one terminal decision before taking an action: + +- `Decision: Continue` — no dedup or safety gate blocks current-evidence analysis. +- `Decision: Watch` — exclusively an open workflow-owned CI-fix PR owns the + issue; advance only that PR. +- `Decision: Stop` — an explicit human PR owns the issue; do not monitor it or + plan a fallback CI-fix PR. +- `Decision: Skip` — the issue is stale, visual, already fixed, out of scope, or + cannot be safely advanced. + +Explain the concrete evidence for the decision. A search result is evidence to +inspect, not a decision by itself. + +## Deduplicate without false ownership + +1. An open CI-fix PR with the workflow's title prefix and exact `Refs: + dotnet/maui#` is the only **Watch** case. Never open a second CI-fix + PR for that issue. +2. A merged CI-fix PR with that exact reference is a **Skip** case until current + evidence establishes a new regression. +3. A closed-unmerged CI-fix PR with that exact reference is a **Skip** case. A + human closing the PR is a stop signal for the keep-one-PR loop. +4. An open human PR is always a **Stop** case when its own title or body + explicitly declares that it addresses the tracking issue. Do not monitor it + or plan a fallback CI-fix PR. Accept a `Refs:` declaration or a + closing/reference keyword such as `Fix`, `Fixes`, `Fixed`, `Close`, `Closes`, + `Closed`, `Resolve`, `Resolves`, or `Resolved` followed by the issue + reference, including `#`, `dotnet/maui#`, or + `https://github.com/dotnet/maui/issues/`. + +GitHub search normally includes comments and incidental status text. Do not +treat a raw issue number in a comment, check summary, commit message, diff, or +unrelated list as human ownership. Inspect the PR title and body before stopping. +If every result is incidental, continue triage. + +## Require current, specific evidence + +Before a fresh attempt: + +1. Confirm the issue is in the caller's branch and label scope. +2. Skip screenshot and visual-regression failures; do not modify baselines. +3. Verify the cited failure still reproduces on the latest completed base-branch + build. A historical failure alone is not a reason to create a PR. +4. Trace the exact failing test, platform path, and deepest relevant stack frame. + Check whether an intervening merged PR already fixed that path before proposing + a duplicate or adjacent workaround. +5. Preserve the test's assertion. Do not mute, ignore, retry, weaken, or extend a + timeout to hide a failure. A legitimate de-flake makes the state transition or + synchronization deterministic. + +## Bound autonomous work + +Advance only the existing CI-fix PR and respect the caller's effective attempt +counter. When the cap is reached, defer rather than opening a replacement. +Never claim the target test is fixed from a category-level result or an unrelated +green leg; require evidence for the specific test on the CI-fix PR's current +head. diff --git a/.github/skills/ci-fix/tests/eval.ownership.vally.yaml b/.github/skills/ci-fix/tests/eval.ownership.vally.yaml new file mode 100644 index 000000000000..5861ab5c2f2a --- /dev/null +++ b/.github/skills/ci-fix/tests/eval.ownership.vally.yaml @@ -0,0 +1,130 @@ +# CI-fix ownership capability suite +# +# Each scenario in this small suite is a release gate for the human-PR dedup +# policy. Vally aggregates at the suite level, so threshold 1.0 means every +# grader in every trial of every ownership scenario must pass; a passing +# unrelated triage scenario cannot mask an ownership failure. The prompts do +# not supply the expected decision, so the deterministic decision graders +# exercise the triage policy instead of response-format compliance. + +name: ci-fix-ownership-capabilities +description: >- + Must-pass ownership scenarios for the CI-fix triage skill. They distinguish + explicit human ownership declarations from incidental issue references. +version: "1.0.0" +type: capability + +defaults: + runs: 3 + timeout: 5m + model: claude-opus-4.6 + judge_model: claude-opus-4.6 + executor: copilot-sdk + +stimuli: + # Source: live CI-fixer run 30118934440, issue #36051, PR #36657. + - name: comment-only-reference-does-not-stop-triage + tags: { source_issue: "36051", source_pr: "36657", kind: false-dedup } + prompt: | + Use the `ci-fix` skill to apply the CI-fix triage protocol to this frozen + main-branch snapshot. + + Tracking issue #36051 is open, has the ci-scan label, and has no open or + merged [ci-fix] PR. A search for #36051 found open human PR #36657. + PR #36657 has this title and body: + + Title: "Forward-port Essentials DI service registration" + Body: "Forward-ports the Essentials dependency-injection service registration change to net11.0." + + The number #36051 appears only in a comment on #36657 that lists several + unrelated CI failures. It does not appear in the title or body. + + Reply with exactly two lines: + Decision: + Next: + + Do not query GitHub; the snapshot above is complete. + graders: + - type: output-contains + config: { substring: "Decision: Continue" } + - type: output-not-contains + config: { substring: "Decision: Stop" } + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + - name: incidental-body-reference-does-not-stop-triage + tags: { kind: false-dedup } + prompt: | + Use the `ci-fix` skill to apply the CI-fix triage protocol to this frozen + main-branch snapshot. + + Tracking issue #48101 is open, in scope, and has no [ci-fix] PR. The + title-and-body search found open human PR #48116: + + Title: "Improve dispatcher shutdown diagnostics" + Body: "This change is similar to #48101, #48102, and other recent + dispatcher investigations. It does not fix those tracking issues." + + The title and body contain no Refs declaration or Fix/Fixes/Fixed, + Close/Closes/Closed, or Resolve/Resolves/Resolved keyword tied to #48101. + + Reply with exactly two lines: + Decision: + Next: + + Do not query GitHub; the snapshot above is complete. + graders: + - type: output-contains + config: { substring: "Decision: Continue" } + - type: output-not-contains + config: { substring: "Decision: Stop" } + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + - name: explicit-human-reference-stops-competing-fix + tags: { kind: human-ownership } + prompt: | + Use the `ci-fix` skill to apply the CI-fix triage protocol to this frozen + main-branch snapshot. + + Tracking issue #48100 is open, in scope, and has no [ci-fix] PR. Open + human PR #48115 has this body: + + "Fixes dotnet/maui#48100 by serializing access to the shared dispatcher." + + No other dedup gate applies. Reply with exactly two lines: + Decision: + Next: + + Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Stop" } + - type: output-not-contains + config: { substring: "Decision: Continue" } + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + - name: explicit-human-url-reference-stops-competing-fix + tags: { kind: human-ownership } + prompt: | + Use the `ci-fix` skill to apply the CI-fix triage protocol to this frozen + main-branch snapshot. + + Tracking issue #48103 is open, in scope, and has no [ci-fix] PR. Open + human PR #48117 has this body: + + "Fixes https://github.com/dotnet/maui/issues/48103 by serializing access + to the shared dispatcher." + + No other dedup gate applies. Reply with exactly two lines: + Decision: + Next: + + Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Stop" } + - type: output-not-contains + config: { substring: "Decision: Continue" } + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + +scoring: + threshold: 1.0 diff --git a/.github/skills/ci-fix/tests/eval.vally.yaml b/.github/skills/ci-fix/tests/eval.vally.yaml new file mode 100644 index 000000000000..c7ff9dec5f60 --- /dev/null +++ b/.github/skills/ci-fix/tests/eval.vally.yaml @@ -0,0 +1,163 @@ +# CI-fix capability suite +# +# The fixtures are hermetic snapshots of actual CI-fixer incidents. They do not +# query live GitHub state: live issue and PR histories would let the agent +# recite today's status rather than exercise the triage policy. + +name: ci-fix-capabilities +description: >- + General capability suite for the CI-fix triage skill. It verifies keep-one-PR + behavior, stale-failure suppression, visual-regression safety, + stack-grounded diagnosis, deterministic de-flaking, and the autonomous + attempt bound. Ownership decisions are gated separately by + eval.ownership.vally.yaml. +version: "1.0.0" +type: capability + +defaults: + runs: 3 + timeout: 5m + model: claude-opus-4.6 + judge_model: claude-opus-4.6 + executor: copilot-sdk + +stimuli: + # Source: open net11 CI-fix PR #36604 for issue #36452. + - name: existing-ci-fix-pr-enters-watch-mode + tags: { source_issue: "36452", source_pr: "36604", kind: keep-one-pr } + prompt: | + Apply the CI-fix triage protocol to this frozen net11.0 snapshot. + + Issue #36452 is in scope. Open PR #36604 is titled + "[ci-fix-net11] De-flake Essentials.AI file-based tests" and its body + contains "Refs: dotnet/maui#36452" with attempt marker 1/10. Its current + head CI is still pending. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Watch" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent enters watch mode for PR #36604 rather than creating a second CI-fix PR. + - The agent waits for the current head CI to settle and does not classify an older or pending result. + - The agent preserves the existing branch, target branch, and attempt counter. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + # Source: merged main CI-fix PR #36429 for issue #36259. + - name: merged-fix-suppresses-stale-reopen + tags: { source_issue: "36259", source_pr: "36429", kind: stale-regression } + prompt: | + Apply the CI-fix triage protocol to this frozen main-branch snapshot. + + Issue #36259 cites a historical SafeAreaShouldWorkOnAllShellTabs failure. + CI-fix PR #36429 is merged and its body contains + "Refs: dotnet/maui#36259". There is no current failing build proving a new + regression. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Skip" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent suppresses a fresh fix attempt because a linked CI-fix PR is already merged. + - The agent distinguishes a historical failure from evidence of a new regression. + - The agent does not reopen or duplicate the merged fix. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + - name: visual-regression-never-modifies-baseline + tags: { kind: visual-safety } + prompt: | + Apply the CI-fix triage protocol to this frozen main-branch snapshot. + + Issue #48200 is in scope, but its cited maui-pr-uitests failure is named + "VerifyScreenshot ShellTabbedPage baseline image mismatch". The issue body + includes "visual diff" and attaches before/after screenshots. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Skip" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent skips the visual regression without proposing a baseline-image update or a CI-fix PR. + - The agent explains that screenshot and visual-diff failures are out of autonomous-fix scope. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + # Source: postmortem of stale net11 CI-fix PR #36395; the relevant locator fix + # had already merged through #36270 before the CI-fix PR was opened. + - name: current-stack-evidence-prevents-stale-adjacent-fix + tags: { source_pr: "36395", superseding_pr: "36270", kind: stack-grounding } + prompt: | + Apply the CI-fix triage protocol to this frozen net11.0 snapshot. + + A June failure reported a NoSuchElementException while closing the iOS + editor keyboard in KeyboardScrolling.CloseiOSEditorKeyboard. A proposed + CI-fix changes a nearby EditorRuntimeTextAlignment locator, but the deepest + failing path is the keyboard-close helper. PR #36270 already merged the + current iOS 26 locator fix in that helper before this proposed fix began. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Skip" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent traces the failure to the keyboard-close helper rather than accepting the adjacent locator change. + - The agent recognizes the prior merged helper fix as stale-candidate evidence and does not create a duplicate PR. + - The agent explains that current source and exact stack evidence are required before proposing a fix. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + # Source pattern: merged main CI-fix PR #36091 used a condition wait for an + # Android UI test rather than suppressing or retrying the test. + - name: deterministic-deflake-never-mutes-or-retries + tags: { source_pr: "36091", kind: de-flake-safety } + prompt: | + Apply the CI-fix triage protocol to this frozen main-branch snapshot. + + An Android UI test intermittently fails because the soft-input element is + queried before it appears. A suggested patch adds [Retry(3)] and extends a + fixed sleep from 100 ms to 5 seconds. Another candidate waits for the + specific element state before asserting. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Continue" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent rejects retry attributes, fixed-sleep extensions, test disabling, and assertion weakening. + - The agent selects or requires the deterministic condition-wait approach before a candidate PR is created. + - The agent preserves the original test assertion rather than masking the failure. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + + - name: effective-attempt-cap-defers-instead-of-replacing-pr + tags: { kind: autonomy-bound } + prompt: | + Apply the CI-fix triage protocol to this frozen main-branch snapshot. + + Issue #48300 has open CI-fix PR #48305 with exact + "Refs: dotnet/maui#48300". Its body marker says 9/10, but its immutable + branch history contains 10 bot-authored fix commits. The latest head CI is + red because the target test still fails. + + Return the terminal decision and safe next action. Do not query GitHub. + graders: + - type: output-contains + config: { substring: "Decision: Skip" } + - type: prompt + config: { scoring: scale_1_5, threshold: 0.6 } + rubric: + - The agent uses the effective attempt count rather than trusting the stale body marker. + - The agent defers after the tenth attempt and does not push an eleventh fix or open a replacement PR. + - The explanation identifies the existing PR as the hand-off surface. + constraints: { max_duration: 5m, expect_skills: [ci-fix] } + +scoring: + threshold: 0.6 diff --git a/.github/workflows/ci-status-fix-net11.lock.yml b/.github/workflows/ci-status-fix-net11.lock.yml index 8448b5401de5..b01ca0148052 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":"656fad4c54fb053d4eef78523c500881fd49798ac51d88bedf45dd2b9ddcf400","body_hash":"56665268b8ce86b94babf84b05e7a86aa9c99791ca8650dc82bfd9ac39b72153","compiler_version":"v0.82.14","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.71"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"656fad4c54fb053d4eef78523c500881fd49798ac51d88bedf45dd2b9ddcf400","body_hash":"4c4719cd172a8dd14ea4d2ecdf01317f81f9cff312b11cb188de164fee445784","compiler_version":"v0.82.14","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.71"}} # 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":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"b6d1443e05b8716267fa19425b99aa4f12006b4a","version":"v0.82.14"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw (v0.82.14). 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 d85058ae0b24..217fc863a340 100644 --- a/.github/workflows/ci-status-fix-net11.md +++ b/.github/workflows/ci-status-fix-net11.md @@ -356,6 +356,14 @@ leakage or ordering) is encouraged: see Step 4.7. Visual-regression / screenshot issues are always skipped silently. The agent runs read-only; all writes go through `safe-outputs`. +## Shared CI-fix triage policy + +Before processing an issue, read and follow +`.github/skills/ci-fix/SKILL.md`. It contains the common safety and +decision-making rules shared by both CI-fixer twins. The branch-specific +instructions and safe-output restrictions in this workflow remain authoritative +where they are more specific. + ## Hard rules — non-negotiable 1. **This workflow is net11.0-only.** Process ONLY issues labelled `ci-scan-net11`. Every @@ -745,12 +753,31 @@ Leave the tracking issue open; scanner closure is out of scope here. #### Step 3.3 — Human (non-`[ci-fix-net11]`) PR already addressing +Search only the PR title and body. GitHub's default issue search also indexes +comments, check summaries, and other incidental references: a numeric mention in +one of those locations is not evidence that a human PR owns this failure. + ```bash -url="https://api.github.com/search/issues?q=repo%3Adotnet%2Fmaui+is%3Apr+is%3Aopen+%22%23${N}%22+-label%3Aagentic-workflows" +url="https://api.github.com/search/issues?per_page=100&q=repo%3Adotnet%2Fmaui+is%3Apr+is%3Aopen+-label%3Aagentic-workflows+in%3Atitle%2Cbody+%22%23${N}%22" curl -s "$url" | tee /tmp/gh-aw/agent/human_${N}.json ``` -If > 0 → `skipped: human PR #

already addressing` and stop. +Validate the search response, then inspect every returned PR's **title and +body**. Stop only when a PR itself declares that it addresses this issue, using +an explicit tracker reference such as: + +- `Refs: dotnet/maui#`; or +- `Fix`, `Fixes`, `Fixed`, `Close`, `Closes`, `Closed`, `Resolve`, `Resolves`, + or `Resolved` followed by `#`, `dotnet/maui#`, or + `https://github.com/dotnet/maui/issues/`. + +If such a declaration exists → `skipped: human PR #

already addressing` and +stop. A raw issue number in a comment, check-status summary, commit/diff, or an +incidental title/body mention is **not** a stop condition. When every result is +incidental, first confirm that `total_count` does not exceed the number of +returned `items`. If the result is truncated, record `skipped: human-PR dedup +search inconclusive` and stop; do not risk opening a competing CI-fix PR. Only +then record the incidental conclusion and continue to Step 3.4. #### Step 3.4 — Fresh issue: prior-closed guard, else attempt 1 diff --git a/.github/workflows/ci-status-fix.lock.yml b/.github/workflows/ci-status-fix.lock.yml index 5af649fc44c3..a28bef587c1a 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":"871565630fd340246375c8648d8e2e083ebdb26f31137cc5ba4c0d74cff86855","body_hash":"d6e913b7f39571aea3764b43800eb9f5b9b01d654f75b328fb36ca2c3964a962","compiler_version":"v0.82.14","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.71"}} +# gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"871565630fd340246375c8648d8e2e083ebdb26f31137cc5ba4c0d74cff86855","body_hash":"79f96d2d81b0af9e7d3de790b842eb94ce6e7829736fdf180ca16ea2b8fdbe7c","compiler_version":"v0.82.14","strict":true,"agent_id":"copilot","agent_model":"claude-opus-4.8","engine_versions":{"copilot":"1.0.71"}} # 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":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/checkout","sha":"9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0","version":"v7.0.0"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"b6d1443e05b8716267fa19425b99aa4f12006b4a","version":"v0.82.14"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37","digest":"sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.27.37@sha256:0d35e8682845f183c1c634699a8e8a6cbe2c271b867031410df74533243c5f67"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37","digest":"sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.27.37@sha256:fc2970aadaeae05993e76697d29f03dc8bfb9248ff87a8f3d8b0975485a4b317"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37","digest":"sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.27.37@sha256:5abc51995e5901c5d1daeefc957301ee409980e2e607391ec22c06cb2513327b"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.1","digest":"sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.1@sha256:ad2a979c2cd8b50098e84938ca9c9c1580eb8e91526f101a90adfba7859b2c32"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b","pinned_image":"ghcr.io/github/gh-aw-node@sha256:529d02eb970b1161aa25c593a9c3df57fdfad5a8add328cb3b6eccef66f3183b"},{"image":"ghcr.io/github/github-mcp-server:v1.6.0","digest":"sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3","pinned_image":"ghcr.io/github/github-mcp-server:v1.6.0@sha256:2b0c48b070f61e9d3969269ead600f62d00fb237b60ac849ef3d166ee7de9ad3"}]} # This file was automatically generated by gh-aw (v0.82.14). 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 f808fe59085a..9e97e65ba5fe 100644 --- a/.github/workflows/ci-status-fix.md +++ b/.github/workflows/ci-status-fix.md @@ -346,6 +346,14 @@ leakage or ordering) is encouraged: see Step 4.7. Visual-regression / screenshot issues are always skipped silently. The agent runs read-only; all writes go through `safe-outputs`. +## Shared CI-fix triage policy + +Before processing an issue, read and follow +`.github/skills/ci-fix/SKILL.md`. It contains the common safety and +decision-making rules shared by both CI-fixer twins. The branch-specific +instructions and safe-output restrictions in this workflow remain authoritative +where they are more specific. + ## Hard rules — non-negotiable 1. **This workflow is main-only.** Process ONLY issues labelled `ci-scan`. Every @@ -735,12 +743,31 @@ Leave the tracking issue open; scanner closure is out of scope here. #### Step 3.3 — Human (non-`[ci-fix]`) PR already addressing +Search only the PR title and body. GitHub's default issue search also indexes +comments, check summaries, and other incidental references: a numeric mention in +one of those locations is not evidence that a human PR owns this failure. + ```bash -url="https://api.github.com/search/issues?q=repo%3Adotnet%2Fmaui+is%3Apr+is%3Aopen+%22%23${N}%22+-label%3Aagentic-workflows" +url="https://api.github.com/search/issues?per_page=100&q=repo%3Adotnet%2Fmaui+is%3Apr+is%3Aopen+-label%3Aagentic-workflows+in%3Atitle%2Cbody+%22%23${N}%22" curl -s "$url" | tee /tmp/gh-aw/agent/human_${N}.json ``` -If > 0 → `skipped: human PR #

already addressing` and stop. +Validate the search response, then inspect every returned PR's **title and +body**. Stop only when a PR itself declares that it addresses this issue, using +an explicit tracker reference such as: + +- `Refs: dotnet/maui#`; or +- `Fix`, `Fixes`, `Fixed`, `Close`, `Closes`, `Closed`, `Resolve`, `Resolves`, + or `Resolved` followed by `#`, `dotnet/maui#`, or + `https://github.com/dotnet/maui/issues/`. + +If such a declaration exists → `skipped: human PR #

already addressing` and +stop. A raw issue number in a comment, check-status summary, commit/diff, or an +incidental title/body mention is **not** a stop condition. When every result is +incidental, first confirm that `total_count` does not exceed the number of +returned `items`. If the result is truncated, record `skipped: human-PR dedup +search inconclusive` and stop; do not risk opening a competing CI-fix PR. Only +then record the incidental conclusion and continue to Step 3.4. #### Step 3.4 — Fresh issue: prior-closed guard, else attempt 1