Skip to content

69% of development push runs are cancelled: the release loop outruns Code Quality #526

Description

@rubenvdlinde

69% of the fleet's development push runs are cancelled — the release loop outruns CI

Measured 2026-08-20, last ≤15 completed Code Quality push runs per app on development:

repo runs cancelled success failure
openregister 8 7 1 0
opencatalogi 13 12 1 0
openconnector 7 2 4 1
docudesk 10 9 1 0
nldesign 14 1 13 0
launchpad 15 2 12 1
softwarecatalog 11 10 1 0
larpingapp 11 10 1 0
zaakafhandelapp 11 10 1 0
procest 11 10 1 0
pipelinq 11 10 1 0
shillinq 9 8 0 1
scholiq 10 9 1 0
portaliq 12 6 6 0
decidesk 13 12 1 0
openbuild 12 5 4 3
doriath 13 8 5 0
hermiq 9 8 1 0
fleet 200 139 (69%) 55 6

Mechanism — measured, not inferred

quality.yml carries, correctly:

concurrency:
  group: quality-${{ github.ref }}
  cancel-in-progress: true

The group is keyed on the branch, so a new push to development cancels the in-flight verification of the previous one. That is the right design — once commit N+1 exists, verifying N matters less.

The failure is one of cadence, not of the concurrency rule:

  • Merges into development arrive every 8–12 minutes. An automated release cycle pushes chore(release): X.Y.Z-unstable.<ts> [skip ci], then a release/vX PR is merged. Observed on decidesk, scholiq, shillinq, hermiq simultaneously.
  • A Code Quality run takes 14–23 minutes (decidesk median 14, scholiq median 23; 30–42 jobs including a PHPUnit matrix and Playwright).

Because the run is slower than the interval, the newest commit's run is cancelled too. The branch never converges to a verdict — it only does so during a lull, which is exactly what the 55 successes are.

Why this matters more than it looks

A cancelled run is not a failure, but it is not a pass either. It is no verdict at all, and it renders identically to "nothing wrong here" in every summary that counts failures. Roughly two thirds of what lands on development is currently unverified.

It also undermines the gate-drift routine tracked in #523: even once FLEET_DISPATCH_TOKEN is provisioned, a Friday sweep dispatching Code Quality on development will be cancelled by the next release merge, because a workflow_dispatch run shares the same quality-refs/heads/development concurrency group. Provisioning the token is necessary but not sufficient.

Options (needs a decision — I have not changed anything here)

  1. Throttle the release loop — batch the unstable releases (e.g. hourly) so CI has room to finish. Highest signal recovered per unit of change.
  2. Give sweeps their own concurrency group — e.g. group: quality-${{ github.ref }}-${{ github.event_name }}, so a dispatched drift sweep is not cancelled by a routine merge. Fixes Fleet gate-drift detection has never run: FLEET_DISPATCH_TOKEN is not provisioned #523's interaction but not the everyday gap.
  3. Accept it and verify at the promotion boundary instead — treat development as explicitly unverified and make dev→beta the real gate. Honest, but it moves the discovery of breakage much later.

My recommendation is 1 + 2: the loop is the root cause, and the concurrency-group split keeps the drift sweep meaningful regardless of merge traffic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions