name: workflow hygiene # Properties of the workflows themselves, checked rather than remembered. # # Two properties today. The first: every workflow declares a concurrency group # that varies by ref. None of them did until 2026-10-05, and the consequence was not # a slow build — it was that CI stopped being usable for anyone. A session # pushing four versions of a branch queued four complete sets of runs, all of # which had to drain; one PR's 21 contexts settled none in 70 minutes behind a # backlog of 25, and two PRs were merged on locally-executed equivalents # because the gate could not run. One omitted block reintroduces that for the # whole repo, invisibly: the workflow still passes, it just queues forever # under load. # # **The path gate.** `scripts/pr-touches-paths.py` decides whether a # path-filtered workflow's jobs do any work, from the pull request's own diff — # because Forgejo matches a `paths:` filter against the push delta, so a rebase # fires every path-filtered workflow in the repo (measured: a jcp-only change # ran 2 workflows pushed fresh and 15 force-pushed after a rebase). A gate that # decides whether tests run is load-bearing in the dangerous direction: a wrong # `false` silently skips a workflow. Its self-test pins both directions and that # every way of failing fails *open*. # # This job runs on `linux`, which is jetson-hub — deliberately not the dev Mac, # which already serves 13 of this repo's 21 contexts through two runners. It # needs no toolchain and finishes in seconds. on: push: branches: [main] pull_request: paths: - '.github/workflows/**' - 'scripts/check-workflow-concurrency.sh' - 'scripts/check-workflow-concurrency-selftest.sh' - 'scripts/pr-touches-paths.py' - 'scripts/pr-touches-paths-selftest.sh' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: concurrency-groups: name: every workflow supersedes its own queue runs-on: linux steps: - uses: actions/checkout@v4 # The check must be able to fail, or it is decoration. The self-test # breaks the property both ways against a scratch copy and asserts the # check rejects each. It lives in a script because embedding its Python # in this `run:` block made the file invalid YAML, which would have meant # no CI at all. - name: The check fails closed (self-test) run: ./scripts/check-workflow-concurrency-selftest.sh - name: Every workflow is grouped per ref run: ./scripts/check-workflow-concurrency.sh # The path gate fails open in every failure mode, and still answers # `false` for a diff that cannot affect the workflow. - name: The path gate fails open (self-test) run: ./scripts/pr-touches-paths-selftest.sh