From ab338699589384a01cd7fcfe44694f379f1a9b8d Mon Sep 17 00:00:00 2001 From: Julien Martel Date: Sat, 12 Sep 2026 03:46:37 -0500 Subject: [PATCH 1/2] tests: one run per commit, and nothing from apt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `push: branches: ['**']` meant every push to a PR branch fired this twice — once as `push`, once as `pull_request` — for one commit and one answer. Sixty push runs against twenty-three PR runs in the last two weeks says how much of that was the duplicate. Main only now; PRs are covered by the `pull_request` trigger they already had. The install step asked apt for three tools and the ubuntu-latest image already had two of them. bats comes from npm (preinstalled, and what haus's shell job uses); shellcheck and jq come from the image, with jq still named — the tier filter IS a jq program — as its own version print, so an image that dropped it fails loudly rather than turning every case into an error. `concurrency` cancels a superseded run on a PR branch. Main is exempt: every push there is a commit whose tick someone may read back. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011wToFna2AmAJdZzJwqEKQs --- .github/workflows/test.yml | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 490c6fb..09718fb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,9 +43,17 @@ name: Tests on: push: - branches: ['**'] + branches: [main] pull_request: +# A second push to a PR branch makes the first run's answer worthless, and the +# abandoned run still holds a runner — on the macOS ones, a queue slot the next +# PR then waits behind. Only PR runs cancel: a push to main is a distinct commit +# whose tick someone may need to read back. +concurrency: + group: tests-${{ github.ref }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + jobs: test: name: bats + shellcheck + skill guards @@ -53,11 +61,20 @@ jobs: steps: - uses: actions/checkout@v4 - # jq is named rather than assumed present: the tier filter IS a jq - # program and the config layer is another, so a runner image that dropped - # it would turn every case into an error rather than a failure. - - name: Install bats + shellcheck + jq - run: sudo apt-get update && sudo apt-get install -y bats shellcheck jq + # bats is the one tool of the three the ubuntu-latest image lacks, and + # npm is preinstalled, so it comes from npm rather than apt. shellcheck + # and jq are already on the image; `apt-get update` in front of them + # bought nothing and, on the day the Azure mirrors go quiet, hangs rather + # than fails (haus/check.yml has the long version of that afternoon). + # + # jq is still named rather than assumed: the tier filter IS a jq program + # and the config layer is another, so an image that dropped it would turn + # every case into an error rather than a failure. The version print below + # is what makes that loud instead of confusing. + - name: Install bats + run: sudo npm install -g bats + - name: jq is on this image + run: jq --version # The versions are printed because they are not pinned, and apt's # shellcheck disagrees with a newer one about which checks are on by From 027e13ea51cba9511d1c2a505257d212633fc437 Mon Sep 17 00:00:00 2001 From: Julien Martel Date: Sat, 12 Sep 2026 04:06:19 -0500 Subject: [PATCH 2/2] tests: keep main out of the concurrency group, and fix the stale header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The block as first written put every main push in one group with cancelling off, which does not do what its own comment promised: a shared group serializes those runs, and GitHub cancels a *pending* run when a newer one joins it — so a merge followed by a bench ship lock bump inside one build's wall clock leaves the middle commit with no run at all. Line 1 still said "on every push and PR" after line 46 stopped being true. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011wToFna2AmAJdZzJwqEKQs --- .github/workflows/test.yml | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 09718fb..846f057 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,4 +1,4 @@ -# Verify factory on every push and PR. +# Verify factory on every push to main, and on every PR. # # What goes wrong with these scripts is not a crash. `factory shift` runs # unattended and its product is a log read hours later, so its worst output is a @@ -47,11 +47,17 @@ on: pull_request: # A second push to a PR branch makes the first run's answer worthless, and the -# abandoned run still holds a runner — on the macOS ones, a queue slot the next -# PR then waits behind. Only PR runs cancel: a push to main is a distinct commit -# whose tick someone may need to read back. +# abandoned run still holds a runner — a runner the next PR then waits +# behind. +# +# Only a PR run is ever in a shared group. Everything else keys on the commit, +# so it gets a group of its own: putting main pushes in one group would +# SERIALIZE them even with cancelling off, and GitHub cancels a *pending* run +# when a newer one joins its group — so three merges inside one build would +# leave the middle commit with no run at all. That is the tick this is +# supposed to protect. concurrency: - group: tests-${{ github.ref }} + group: tests-${{ github.event_name == 'pull_request' && github.ref || github.sha }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: