From d83754bb2c0772ae7316820d472e28a1b708783e Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Fri, 14 Aug 2026 10:11:57 +0300 Subject: [PATCH 1/2] ci: qodo-gate sweeps its own stale red runs off the head commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .github/workflows/qodo-gate.yml | 44 +++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/.github/workflows/qodo-gate.yml b/.github/workflows/qodo-gate.yml index aa9f05f..7ed6e11 100644 --- a/.github/workflows/qodo-gate.yml +++ b/.github/workflows/qodo-gate.yml @@ -20,11 +20,20 @@ # Event-driven: re-evaluates when the PR updates, when a review is submitted, # and when someone replies in a review thread. GitHub's workflow parser # rejects the documented `pull_request_review_thread` trigger ("Unexpected -# value"), so plain thread resolution does not auto-retrigger — after -# resolving the last thread, either leave a reply (retriggers) or Re-run the -# failed qodo-gate check from the PR's Checks tab; the check reads the live -# resolution state each run. Escape hatch for a Qodo outage: the -# `skip-qodo-gate` label passes the check (label changes re-trigger it). +# value" — re-verified empirically, zero-job "workflow file issue" run), so +# plain thread resolution does not auto-retrigger — after resolving the last +# thread, leave a reply (retriggers); the check reads the live resolution +# state each run. Escape hatch for a Qodo outage: the `skip-qodo-gate` label +# passes the check (label changes re-trigger it). +# +# A passing run also re-runs this workflow's earlier FAILED runs on the same +# head commit. Each trigger event creates its own workflow run, and branch +# protection's rollup counts every run of a required check on the commit — a +# fresh green run sits beside the stale red ones rather than superseding +# them, so the PR stays BLOCKED until each red run is re-run by hand (four +# clicks on PR #396). Only a passing run re-runs others and a re-run that +# passes finds nothing red left, so it converges; if threads are genuinely +# unresolved the re-runs go red again and the gate still holds. name: qodo-gate on: pull_request: @@ -37,6 +46,7 @@ on: permissions: contents: read pull-requests: read + actions: write jobs: qodo-gate: @@ -133,9 +143,29 @@ jobs: echo "FAIL: $unresolved unresolved Qodo review thread(s) — address" echo "or explicitly dismiss each finding in its thread, then mark" echo "it resolved. Plain resolution does not auto-retrigger this" - echo "check: leave a reply in a thread (retriggers) or Re-run the" - echo "check from the PR's Checks tab after resolving." + echo "check: leave a reply in a thread (retriggers) — the passing" + echo "run then sweeps this red run off the commit itself." exit 1 fi echo "PASS: Qodo review present, all its threads resolved" + + # Sweep stale red runs of this gate off the head commit, so the pass + # above is the one the branch-protection rollup sees. Best-effort: a + # failed re-run request must not turn a PASS into a FAIL. + - name: Re-run this gate's earlier failed runs on this commit + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + THIS_RUN: ${{ github.run_id }} + run: | + set -uo pipefail + gh run list --repo "$REPO" --workflow qodo-gate \ + --commit "$HEAD_SHA" --json databaseId,conclusion \ + --jq '.[] | select(.conclusion == "failure") | .databaseId' | + while read -r id; do + [ "$id" = "$THIS_RUN" ] && continue + echo "re-running failed qodo-gate run $id" + gh run rerun "$id" --repo "$REPO" --failed || true + done From 47abac370c702bb71c93a2dba18cc8aba650e7b6 Mon Sep 17 00:00:00 2001 From: Joseph <162703152+josephnef@users.noreply.github.com> Date: Fri, 14 Aug 2026 10:20:40 +0300 Subject: [PATCH 2/2] ci: guard the sweep's run listing so it cannot fail a passing gate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .github/workflows/qodo-gate.yml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/.github/workflows/qodo-gate.yml b/.github/workflows/qodo-gate.yml index 7ed6e11..2085a35 100644 --- a/.github/workflows/qodo-gate.yml +++ b/.github/workflows/qodo-gate.yml @@ -160,12 +160,19 @@ jobs: HEAD_SHA: ${{ github.event.pull_request.head.sha }} THIS_RUN: ${{ github.run_id }} run: | - set -uo pipefail - gh run list --repo "$REPO" --workflow qodo-gate \ + set -u + # The listing is guarded too, not just the reruns: with an unguarded + # pipeline a transient list failure would be the step's exit code — + # exactly the PASS-into-FAIL this step promises not to produce. + if ! ids=$(gh run list --repo "$REPO" --workflow qodo-gate \ --commit "$HEAD_SHA" --json databaseId,conclusion \ - --jq '.[] | select(.conclusion == "failure") | .databaseId' | - while read -r id; do + --jq '.[] | select(.conclusion == "failure") | .databaseId'); then + echo "sweep skipped: could not list this workflow's runs" + exit 0 + fi + for id in $ids; do [ "$id" = "$THIS_RUN" ] && continue echo "re-running failed qodo-gate run $id" gh run rerun "$id" --repo "$REPO" --failed || true done + exit 0