Skip to content

ci: qodo-gate sweeps its own stale red runs off the head commit - #397

Merged
josephnef merged 2 commits into
masterfrom
qodo-gate-self-heal
Aug 14, 2026
Merged

ci: qodo-gate sweeps its own stale red runs off the head commit#397
josephnef merged 2 commits into
masterfrom
qodo-gate-self-heal

Conversation

@josephnef

Copy link
Copy Markdown
Collaborator

The friction this removes

Merging #396 surfaced a gap in the gate's unblock flow: after resolving the last Qodo thread, the reply-triggered green run lands beside the stale red runs rather than superseding them — each trigger event type creates its own workflow run, and the branch-protection rollup counts every run of a required check on the head commit. The PR stayed BLOCKED with a green latest run until all four red pull_request-event runs were re-run by hand from the Checks tab.

The fix

A passing run now sweeps: it lists this workflow's failure-conclusion runs on the same head SHA and gh run rerun --faileds each (new actions: write permission). Properties:

  • Convergent: only a PASS triggers sweeps, and a re-run that passes finds nothing red left to sweep.
  • Still a gate: if threads are genuinely unresolved, the swept runs go red again and the check keeps blocking — the sweep can only align the rollup with the live resolution state, never bypass it.
  • Best-effort: the sweep step tolerates individual rerun failures; it cannot turn a PASS into a FAIL.

The failure message now points at the one remaining manual step (reply in a thread to retrigger) instead of also asking for Checks-tab re-runs.

The alternative, re-tested and still dead

Before adding machinery I re-verified the header's claim that GitHub rejects the documented pull_request_review_thread trigger — if that parsed, plain thread resolution would retrigger the gate and most of this would be unnecessary. It still doesn't: a scratch workflow carrying pull_request_review_thread: {types: [resolved, unresolved]} produced a zero-job "workflow file issue" run on push (run 31778980528). The header comment now records that this was re-verified empirically, not just inherited.

What this does not change

The gate's semantics are untouched: not pinned to head (the anti-treadmill rationale stands), skip-qodo-gate label escape hatch, pagination, thread-attribution logic — all as before. One net-new permission (actions: write), scoped to the workflow's own runs by construction (--workflow qodo-gate --commit <head>).

Validation: YAML parses; the sweep's list/filter pipeline is the same query used to unblock #396 by hand. The self-referential part (a green qodo-gate re-running red qodo-gates) can only be observed on a PR that first goes red and then resolves — this PR itself will exercise the gate normally.

🤖 Generated with Claude Code

Each trigger event type creates its own workflow run, and the
branch-protection rollup counts every run of a required check on the
commit — so after resolving the last Qodo thread, the reply-triggered
green run lands beside the stale red pull_request-event runs instead of
superseding them, and the PR stays BLOCKED until each red run is re-run
by hand from the Checks tab (four of them on the last PR).

A passing run now re-runs this workflow's earlier failed runs on the
same head SHA (actions: write + gh run rerun --failed). Convergent by
construction: only a PASS sweeps, and a re-run that passes finds
nothing red left; if threads are genuinely unresolved the re-runs go
red again and the gate still holds. Best-effort — a failed re-run
request cannot turn the PASS into a FAIL.

Also re-verified the header's parser claim before reaching for the
alternative: pull_request_review_thread is still rejected on push
(zero-job "workflow file issue" run), so thread resolution still
cannot retrigger directly and the reply-to-retrigger flow stays.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

ci: qodo-gate self-heals by re-running stale failed runs on head SHA

🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Add a post-PASS sweep to re-run earlier failed qodo-gate runs on the same commit.
• Fix branch-protection rollup staying blocked due to stale red runs from other trigger events.
• Clarify trigger limitation and update failure guidance to the single required manual retrigger
 step.
Diagram

graph TD
  A["PR / review events"] --> B["qodo-gate workflow"] --> C["Query Qodo review + threads"] --> D["Compute unresolved count"]
  D -->|"unresolved > 0"| E["FAIL (gate blocks)"] --> H["Branch protection rollup"]
  D -->|"unresolved = 0"| F["PASS"] --> G["Sweep: re-run failed qodo-gate runs (same SHA)"] --> H["Branch protection rollup"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use workflow concurrency to reduce duplicate runs
  • ➕ Can cancel in-progress older runs for the same PR, reducing noise
  • ➕ No need for actions: write permissions
  • ➖ Does not fix already-completed failed runs that remain in branch-protection rollup
  • ➖ Does not address the core issue: multiple completed runs on the same SHA
2. Create a separate “single source of truth” check via Checks API
  • ➕ Could publish one canonical check result per commit/PR regardless of workflow run history
  • ➕ Avoids branch protection aggregating multiple workflow runs of the same check
  • ➖ Significantly more complexity and maintenance (custom check-run lifecycle)
  • ➖ Requires careful auth/scoping and more extensive error handling
3. Trigger on pull_request_review_thread resolution events
  • ➕ Would remove the need for reply-to-retrigger and stale-run sweeping
  • ➕ More direct mapping from thread resolution to gate evaluation
  • ➖ Not viable: GitHub workflow parser rejects pull_request_review_thread (as documented in the workflow header)
  • ➖ Would still not guarantee elimination of multiple completed runs per SHA if other triggers fire

Recommendation: The PR’s approach is the most pragmatic: sweeping only after a PASS aligns branch protection with the current resolution state without weakening gating semantics. Concurrency helps reduce run volume but cannot clear completed failures; a custom Checks API publisher is heavier than warranted here.

Files changed (1) +37 / -7

Other (1) +37 / -7
qodo-gate.ymlSelf-heal stale failed qodo-gate runs after a passing evaluation +37/-7

Self-heal stale failed qodo-gate runs after a passing evaluation

• Adds 'actions: write' and a post-pass step that lists this workflow’s failed runs on the PR head SHA and re-runs them best-effort via 'gh run rerun --failed'. Updates the header comment and failure message to reflect the reply-to-retrigger flow and the new sweep behavior.

.github/workflows/qodo-gate.yml

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 14, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Sweep can fail PASS ✓ Resolved 🐞 Bug ☼ Reliability
Description
The new sweep step only tolerates failures from gh run rerun, but if gh run list (or its JSON/JQ
filtering) fails, the step exits non-zero and turns a passing qodo-gate run into a failure. This
contradicts the step’s own “Best-effort…must not turn a PASS into a FAIL” intent and can keep PRs
blocked due to transient GitHub/CLI/API errors.
Code

.github/workflows/qodo-gate.yml[R163-166]

+          set -uo pipefail
+          gh run list --repo "$REPO" --workflow qodo-gate \
+              --commit "$HEAD_SHA" --json databaseId,conclusion \
+              --jq '.[] | select(.conclusion == "failure") | .databaseId' |
Evidence
The workflow claims the sweep is best-effort and must not fail the job, but the implementation only
ignores errors from gh run rerun and does not ignore errors from the upstream gh run list
pipeline, so a list failure will fail the step.

.github/workflows/qodo-gate.yml[153-171]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The sweep step is intended to be best-effort, but the `gh run list ... | while ...` pipeline is not guarded. If listing/filtering prior runs fails (permissions/transient API/CLI issues), the step returns a non-zero exit code and the workflow run fails even after the gate has printed PASS.
## Issue Context
The workflow comment explicitly states the sweep must not convert a PASS into a FAIL, but only `gh run rerun` is protected with `|| true`.
## Fix Focus Areas
- .github/workflows/qodo-gate.yml[153-171]
## Suggested fix
Make the entire sweep step non-fatal by guarding the list operation and/or the pipeline, e.g.:
- Wrap the listing in `if ! ids=$(gh run list ... --jq ...); then echo "skip sweep"; exit 0; fi` and then iterate via `while read -r id; do ...; done <<< "$ids"`.
- Or append `|| true` to the end of the pipeline (`... | while ...; done || true`).
- Alternatively (less precise), set the step to `continue-on-error: true`.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can describe a rule in plain language on the Rules page and Qodo drafts it for you

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/qodo-gate.yml Outdated
The sweep step promised best-effort but only protected the reruns —
with pipefail set, a transient failure of the run listing itself would
have been the step's exit code, turning a PASS into a FAIL. The listing
is now guarded and the step exits 0 on every path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@josephnef
josephnef merged commit a0dfd17 into master Aug 14, 2026
23 checks passed
@josephnef
josephnef deleted the qodo-gate-self-heal branch August 14, 2026 07:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant