From 42d00c2d1909e486e0b1d08560fab1769b9964db Mon Sep 17 00:00:00 2001 From: Cato <41178744+catomean@users.noreply.github.com> Date: Fri, 11 Sep 2026 23:33:06 +0200 Subject: [PATCH] fix(ci): a commit must not cancel another commit's run MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The concurrency group was keyed by branch with cancel-in-progress, so a newer merge cancels an older commit's CI — and every deploy path keys off that run. One that waits for CI to pass on the commit finds a cancelled run and stops. One chained on workflow_run sees conclusion=cancelled and skips. auto-merge also re-arms CI with a dispatch, and under one group-per-branch that dispatch cancels the push run for the SAME commit. Measured across the fleet on 2026-09-11: 28 of 39 ci.yml files had this shape. It broke two repos that day, in the two ways it can break. fleetcrown failed silently — Deploy skipped, four merges sat on main with every check green and nothing red while the box served the previous build, each needing a hand-dispatched deploy. hirnli failed loudly, erroring at its wait-for-CI step, which is the better outcome because somebody sees it. Keying main per commit lets both runs finish, so whatever the deploy path looks for is there. Branch behaviour is unchanged: the newest push is still the only one that matters there. The templates this was copied from are fixed in bitbaum/fleet#53, which also adds a ci-strands-commits rule to the hygiene audit so the remaining repos are found by a sweep rather than by an outage. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_018Z7YRpgsEtNjRqr1usHMQY --- .github/workflows/ci.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0377eca..13a677b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,8 +16,20 @@ on: branches: [main] workflow_dispatch: +# On a branch the newest push is the only one that matters, so cancel the rest. +# +# On main the group is keyed per COMMIT. A commit cancelling a DIFFERENT +# commit's run breaks deployment, because every deploy path keys off that run: +# one that waits for CI to pass on the commit finds a cancelled run and stops, +# and one chained on `workflow_run` sees conclusion=cancelled and skips. +# auto-merge also re-arms CI with a dispatch, which under a single +# group-per-branch cancels the push run for the SAME commit. +# +# Measured 2026-09-11 across the fleet: 28 of 39 ci.yml files had this shape. +# fleetcrown stranded four merges silently (main green, nothing red, the box +# serving the previous build); hirnli failed its deploy loudly at the wait step. concurrency: - group: ci-${{ github.ref }} + group: ci-${{ github.ref }}-${{ github.ref == 'refs/heads/main' && github.sha || 'branch' }} cancel-in-progress: true jobs: