devantler-tech / devantler-tech/ksail
Release runs can be silently dropped, and `turnstyle` can go: adopt `concurrency.queue: max`
- Dominant language
- Go
- Stars
- 165
- Forks
- 12
- Avg merge
- 5h 51m
- Merged PRs (30d)
- 347
Description
> 🤖 Generated by the Agentic Engineer
## Why
GitHub Actions shipped a `queue` key for `concurrency`, and it closes a gap this repo is currently exposed to.
**`cancel-in-progress: false` does not mean "every run eventually executes."** It protects the run that is already executing; the run waiting behind it is still discarded when a newer one arrives:
> By default, any existing `pending` job or workflow in the same concurrency group will be canceled and the new queued job or workflow will take its place.
So on a burst of three events in one group, run 1 executes, **run 2 is silently cancelled**, run 3 executes. There is no failure, no annotation, and nothing in the run list to say a run was dropped.
| `queue` | Meaning |
|---|---|
| `single` (default) | "At most one job or workflow run can be `pending` in the concurrency group." |
| `max` | "Up to 100 jobs or workflow runs can be `pending` in the concurrency group." — FIFO |
`queue: max` with `cancel-in-progress: true` is a validation error, so it only ever applies where cancelling is already switched off.
Announcement: https://github.com/orgs/community/discussions/12835#discussioncomment-16602100
Reference: https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#concurrency
**Proven in this org already:** `devantler-tech/agent-skills` has run `queue: max` in its `release.yaml` since 2026-07-11, with every Release run green since. This is propagating a fix we have already validated, not a trial.
There are two distinct wins in this repo — one correctness, one simplification.
### 1. Release and CD runs can be silently dropped
`release.yaml` (group `Release`), `cd.yaml`, `maintenance.yaml` and `update-skills.yaml` all use `cancel-in-progress: false` with no `queue`. A release landing while another is still publishing means the pending one is discarded.
This is the same failure `devantler-tech/agent-skills` hit and fixed on 2026-07-11 in a PR titled *"serialize Release runs to prevent same-tag race"* — it added `queue: max` to a `Release` group with an identical shape to ksail's. The fix simply has not been propagated here yet.
### 2. `softprops/turnstyle` can likely be retired
`system-test-omni.yaml` and `system-test-hetzner.yaml` both pin `softprops/turnstyle` as a "⏳ Wait for cloud test queue" step, and then gate roughly every subsequent step in the job behind `if: steps.turnstyle.outcome == 'success'`.
That is a userland queue, adopted because native concurrency could not queue properly. It costs us:
- **Billed runner time while waiting** — `abort-after-seconds: 5400` means a waiting run can hold a runner for up to 90 minutes doing nothing but polling the API every 30s. Runs pending under native concurrency consume no runner minutes at all.
- **A third-party action in the supply chain** of a workflow that handles cloud credentials.
- **An `if:` guard threaded through the whole job**, which is noise on every step and easy to forget on a newly added one.
Both workflows already declare a workflow-level group (`system-test-omni` / `system-test-hetzner`) that overlaps with what turnstyle is waiting for. Worth confirming what turnstyle still contributes beyond that group before removing it — but with `queue: max` available, native queueing should now cover the intent, and the action plus every `if:` guard can go.
Note these two workflows are currently `workflow_dispatch`-only (the Omni schedule is paused per ksail#4973), which makes this a low-risk moment to change them.
## What
- Add `queue: max` to the serialized groups that must not drop runs: `Release`, `cd`, `maintenance`, `update-skills`.
- Replace `softprops/turnstyle` in the two system-test workflows with native queueing, and delete the resulting dead `if:` guards.
- For the system-test groups, decide deliberately between `queue: max` (never lose a requested cloud run) and an explicit `queue: single` (avoid stacking expensive cloud runs) — and record which, and why, in the workflow.
- Leave `ci.yaml`'s `cancel-in-progress: true` group alone; cancelling superseded CI is correct.
## Acceptance criteria
- [ ] Release/CD/maintenance/update-skills groups carry `queue: max`; two releases in quick succession both publish, in order.
- [ ] `softprops/turnstyle` no longer appears in this repo, and no orphaned `steps.turnstyle` conditions remain.
- [ ] The system-test workflows still serialize — verified by dispatching two runs and observing the second wait rather than run concurrently or die.
- [ ] Each system-test workflow states its chosen `queue` value explicitly with a one-line rationale.
Part of https://github.com/devantler-tech/monorepo/issues/2453 · Rough size: S
Contributor guide
Assessment
This issue has not been assessed yet.