Skip to content

CI: cancel superseded dev/main push builds - newest SHA wins - #1729

Merged
erikdarlingdata merged 2 commits into
devfrom
feature/ci-superseded-builds
Jul 26, 2026
Merged

CI: cancel superseded dev/main push builds - newest SHA wins#1729
erikdarlingdata merged 2 commits into
devfrom
feature/ci-superseded-builds

Conversation

@erikdarlingdata

Copy link
Copy Markdown
Owner

Summary

Two CI-time items continuing #1712 (docs fast path) and #1715 (PR-level concurrency cancellation + caching):

  1. Superseded push builds now cancel. Push events in build.yml and sql-validation.yml move from unique per-run concurrency groups to a per-branch group with cancel-in-progress: true — a dev merge landing while the previous merge's build is still running cancels the stale run; newest SHA wins. release and merge_group runs keep their unique per-run groups and remain uncancellable.
  2. Merge queue: reported instead of shipped. The requested "exact settings to enable merge queue on dev" cannot honestly be written — merge queue is unavailable on personal-account repositories, verified two independent ways below. Per the instruction to report contradictions in the PR body rather than ship anyway, the full analysis (measured cost, evidence, and the ready-to-click settings if the repo ever moves to an org) is in the Merge queue section.

Baseline: last 30 push-event runs of build.yml on dev

Pulled via gh api (runs + per-run jobs), 2026-07-26. A run is superseded when the next dev push's created_at precedes the run's completion; the reclaimable tail is the time it kept executing after that moment.

  • All 30 of the last 30 dev-push runs happened on 2026-07-26 (the ~20-PR merge train plus follow-ups).
  • 13 of 30 were superseded mid-flight.
  • 60m23s of runner time went to finishing SHAs that were already stale — the exact capacity this PR reclaims, on a shared Windows runner pool that serializes everyone's CI (Execute both Availability Group reads against a real Postgres (#991) #1697).
Full per-run table (30 rows)
Run Created (UTC) SHA Conclusion Duration Jobs Superseded mid-flight? Reclaimable tail
2243 07-26 17:22 3b37bad success 16m28s build 16m25s (success); darling-pg 2m15s (success) no -
2252 07-26 18:02 36332d9 success 18m24s build 18m20s (success); darling-pg 3m14s (success) yes 5m29s
2256 07-26 18:15 67b037a success 19m19s build 19m17s (success); darling-pg 2m23s (success) yes 3m11s
2259 07-26 18:32 7de7842 success 14m58s darling-pg 2m29s (success); build 14m55s (success) yes 9m09s
2262 07-26 18:37 cbad2e4 success 15m02s build 14m58s (success); darling-pg 2m57s (success) yes 5m21s
2268 07-26 18:47 50c8bff success 8m15s darling-pg 3m00s (success); build 8m12s (success) yes 5m15s
2269 07-26 18:50 b66e1cd success 6m41s build 6m38s (success); darling-pg 2m45s (success) no -
2272 07-26 18:57 7aeacfc success 6m10s build 6m07s (success); darling-pg 2m44s (success) yes 4m07s
2275 07-26 18:59 a9ace0e success 7m42s darling-pg 2m46s (success); build 7m39s (success) no -
2284 07-26 19:09 7cf3f39 success 6m08s build 6m05s (success); darling-pg 2m48s (success) yes 5m25s
2285 07-26 19:10 7159a81 success 6m37s darling-pg 3m11s (success); build 6m32s (success) yes 4m39s
2286 07-26 19:12 f8e8372 success 6m40s build 6m36s (success); darling-pg 2m55s (success) yes 5m40s
2287 07-26 19:13 44b3d60 success 6m23s build 6m20s (success); darling-pg 2m38s (success) no -
2294 07-26 19:26 41a7a3b success 7m02s build 6m56s (success); darling-pg 3m04s (success) no -
2296 07-26 19:35 6d6a157 success 6m02s darling-pg 3m12s (success); build 5m58s (success) yes 0m25s
2298 07-26 19:41 35dc49a success 3m41s darling-pg 3m38s (success); build 1m37s (success) no -
2301 07-26 20:00 886d621 success 3m05s darling-pg 3m00s (success); build 1m31s (success) no -
2304 07-26 20:08 97ed4f2 success 6m18s build 6m14s (success); darling-pg 2m42s (success) yes 0m05s
2306 07-26 20:14 56c36f2 success 2m56s darling-pg 2m51s (success); build 1m44s (success) no -
2309 07-26 20:21 626a545 success 6m28s build 6m25s (success); darling-pg 2m52s (success) no -
2312 07-26 20:28 02593dd success 6m16s darling-pg 3m05s (success); build 6m12s (success) yes 4m51s
2313 07-26 20:30 b9fa1dd success 6m48s darling-pg 2m46s (success); build 6m45s (success) no -
2316 07-26 20:44 2e5a818 success 7m08s darling-pg 2m48s (success); build 7m04s (success) no -
2319 07-26 21:02 7be6821 failure 6m30s darling-pg 3m02s (failure); build 6m28s (success) no -
2322 07-26 21:11 83b9000 success 6m50s build 6m46s (success); darling-pg 2m48s (success) no -
2327 07-26 21:30 9cef339 success 6m58s build 6m56s (success); darling-pg 2m56s (success) yes 6m46s
2328 07-26 21:30 6da7968 success 1m36s darling-pg 0m13s (success); build 1m33s (success) no -
2334 07-26 22:11 0e2c370 success 3m08s build 3m05s (success); darling-pg 2m50s (success) no -
2337 07-26 22:15 24591b5 success 3m15s darling-pg 2m54s (success); build 3m11s (success) no -
2339 07-26 22:22 2488298 in_progress - darling-pg 0m15s (success) no -

Verification: nothing consumes intermediate dev-push artifacts

The load-bearing claim behind reversing the earlier "never cancel dev/main push builds" rule. Proven from the workflow graph, not trusted:

What push runs upload: nothing. Every upload-artifact step in the graph, with its gate:

Workflow / step Artifact Gate
build.yml — Upload Lite for signing Lite-unsigned if: github.event_name == 'release'
build.yml — Upload Darling for signing Darling-unsigned release only
build.yml — Upload Lite (Velopack) for signing Lite-Velopack-unsigned release only
build.yml — Upload Darling Viewer (Velopack) for signing DarlingViewer-Velopack-unsigned release only
build.yml darling-pg — Upload PG log and test results darling-pg-failure if: failure() (diagnostics)
nightly.yml darling-pg — Upload PG log and test results darling-pg-failure if: failure() (diagnostics; nightly is untouched by this PR)

sql-validation.yml contains no upload-artifact step at all.

Who downloads artifacts across runs: nobody. Repo-wide search for download-artifact, gh run download, dawidd6/action-download-artifact, nightly.link, and workflow_run triggers: zero matches. The only artifact consumers anywhere are the four SignPath github-artifact-id inputs, and those read same-run step outputs (steps.upload-*.outputs.artifact-id), release-event-only.

Releases build fresh on the release event — every publish/package/sign step runs inside the release run itself; vpk download github pulls from GitHub Releases (the Velopack channel feed), never from Actions artifacts.

Nightly builds its own tree from its own checkout (ref: dev) and publishes to the nightly GitHub release, not to workflow artifacts.

Field deploys (DARLING01) publish locally from a checkout — consistent with the zero-consumer search; no deploy tooling in the repo pulls CI artifacts.

Conclusion: there are no "intermediate dev-push artifacts" to protect — push runs never create any. The justification for the reversal held under verification.

Edges considered and accepted:

  • Failure diagnostics: cancellation could preempt a failing push run before its darling-pg-failure upload. A persistent failure reproduces on the newest SHA with its own diagnostics; one that vanishes on the newest SHA no longer matters.
  • Diff-scoped integration signal: push builds only rebuild the areas their own diff touched, so a cancelled run's areas are not re-verified until the next change touches them. Backstops: every PR already built those areas pre-merge against its merge ref; the nightly builds and tests unconditionally whenever dev changed; the dev→main release PR's diff lights every area.
  • README CI badge: tracks the default branch (main). Dev cancellations never touch it; main sees one push per release cut, so a main supersede is practically impossible — and harmless under the same no-artifacts proof if it ever happens.
  • Required checks: build and Darling PostgreSQL tests gate PRs, and PR-supersede cancellation has existed since CI intelligence: restore the classification the dorny v4 bump broke, cancel superseded PR runs, un-trap the nightly, bound the jobs #1715 — the superseding run always reports on the newest head. Push runs are not required-check contexts. Nothing stops reporting.

What stays uncancellable (unchanged guarantees)

  • release runs: unique build-run-{run_id} group, cancel-in-progress evaluates false. SignPath's manual approval gate can legitimately take hours; nothing can replace or cancel it.
  • merge_group runs: same unique-group treatment (CI: handle merge_group so enabling a dev merge queue is a safe one-click #1716's inert-but-ready wiring).
  • Tag pushes: cannot trigger build.yml at all (push.branches: [main, dev], no tag filter).

Validation

  • The expression idiom (event && format(...) || fallback) is byte-for-byte the short-circuit pattern CI intelligence: restore the classification the dorny v4 bump broke, cancel superseded PR runs, un-trap the nightly, bound the jobs #1715 shipped, extended by one arm; both files parse (checked locally) and this PR's own CI is a full-matrix run (build.yml sits on the root and darling filters), which executes the edited stanza.
  • The instructed throwaway-branch test is not possible, and that contradiction is reported here rather than worked around: build.yml's push trigger is branches: [main, dev] only — two rapid commits to a throwaway branch trigger no runs at all, and widening triggers just to test would be a real behavior change. The new behavior will demonstrate itself on the next rapid dev merge pair; I will link the cancelled run in a comment on this PR when one occurs.

Merge queue (Task 2): cannot be enabled on this repo — reported, not shipped

The requested deliverable ("exact GitHub settings to enable merge queue on dev") contradicts a finding verified twice, most recently today:

What a queue would eliminate, measured against the baseline above: today's train merged ~20 PRs through the auto-merge + CHANGELOG-conflict-repush workflow. Each conflict re-push re-ran PR CI (~15-20 extra full builds over the evening; ~3m40s per single-area re-push after #1715), and the merges themselves produced the 13 superseded dev-push builds / 60m23s in the table. A merge queue serializes candidates so each PR validates exactly once against its final base: both costs go to approximately zero. This PR reclaims the superseded-push slice; the conflict-re-push slice remains structural until the repo is organization-owned.

If the repo ever moves to an organization, the settings are ready to click:

  1. Ruleset on dev → require merge queue; merge method Merge commit (matches repo convention).
  2. Required checks stay build + Darling PostgreSQL tests — both already handle the merge_group event (CI: handle merge_group so enabling a dev merge queue is a safe one-click #1716) and report a result on every queue run (the no-op/fast-path shapes still report).
  3. Concurrency is already compatible: queue runs keep unique, never-cancelled groups (this PR preserves that).
  4. Retire the CHANGELOG-conflict manual re-push loop — the queue rebases and revalidates candidates itself.

No MERGE-QUEUE.md is added: checked-in docs titled "how to enable" for a feature this repo cannot enable would mislead; #1716's CHANGELOG entry records the finding in-repo, and this section is the durable analysis.

Constraints respected

🤖 Generated with Claude Code

erikdarlingdata and others added 2 commits July 26, 2026 18:30
Push events in build.yml and sql-validation.yml now share a per-branch
concurrency group with cancel-in-progress: true, so a dev merge landing
while the previous merge's build is still running cancels the stale run.
Baseline (2026-07-26, last 30 dev-push runs): 13 of 30 superseded
mid-flight, ~60 runner-minutes spent finishing already-stale SHAs.

Verified from the workflow graph before reversing the earlier
never-cancel-push rule: push runs upload no artifacts (every
upload-artifact in build.yml is release- or failure-gated;
sql-validation.yml has none), and no download-artifact, gh run
download, or workflow_run consumer exists anywhere in the repo.
Release and merge_group runs keep unique per-run groups and stay
uncancellable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@erikdarlingdata
erikdarlingdata merged commit 1eb9ac9 into dev Jul 26, 2026
8 checks passed
@erikdarlingdata
erikdarlingdata deleted the feature/ci-superseded-builds branch July 26, 2026 22:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant