Skip to content

ci: cancel superseded runs per ref (ci, schema-drift) - #860

Open
ZacxDev wants to merge 3 commits into
mainfrom
ci/lint-runner-savings
Open

ZacxDev wants to merge 3 commits into
mainfrom
ci/lint-runner-savings

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

Ports the concurrency part of the runner-savings changes from civitai/civitai#6718 and #6728. Only workflow concurrency: blocks change; no job, trigger, condition, permission or secret is touched.

Changes

ci.yml: one concurrency group per ref, cancel-in-progress: true.

  • On a PR, github.ref is refs/pull/N/merge, so a new push to the branch cancels the in-flight run for the older head. The newest head gets its own run, and that is the run branch protection reads.
  • On a push to main, a newer commit cancels the older commit's run. Nothing downstream consumes a per-commit main verdict: there is no workflow_run consumer, and release.yml runs off tags. The newest run checks a tree that contains every older commit. Intermediate commits show cancelled instead of their own verdict. To pin a break to one, push a branch at that commit and dispatch the workflow there.
  • A workflow_dispatch run gets its own dispatch-<ref> group. It neither cancels nor is cancelled by a push or PR run; a re-dispatch on the same ref cancels the older dispatch.
  • Side effect: the Go cache save (build-test, push to main only) is skipped for a cancelled run and happens in the run that superseded it.

schema-drift.yml: the same ref-grouped concurrency. It is not a required check, and only the newest run's answer about the published canonical matters.

Not changed

  • flake.yml: left as on main. It ran once in the last 30 days, so a concurrency group would save nothing.
  • No workflow_dispatch only input. An earlier revision of this PR added one. It was dropped because a narrowed dispatch writes check runs under the normal job names, and a job skipped by if: reports skipped, which branch protection counts as satisfied. At the head of an open PR, a narrowed run could pass required checks that never ran. That includes the webhook-outage recovery case the trigger's comment describes, where the dispatch is the PR's only run. Every job's if: is exactly as on main.
  • No docs-only skip. Six jobs here are required contexts: pins-vs-published, scaffold-currency, build-test, ready-ack-runtime, template-page-vite and dogfood-browser. A workflow-level paths: filter would leave a docs-only PR waiting forever on those. Go tests also read README.md, AGENTS.md, CLAUDE.md and claudedocs/**, so no safe docs set exists.

Required checks

No job, name or condition changed, so every required context reports exactly as before. A cancel only ever stops the run for a superseded commit.

Verification

  • git diff origin/main shows only the two concurrency blocks and their comments: 2 files, +36.
  • actionlint 1.7.12 on ci.yml, schema-drift.yml and flake.yml: no findings. A deliberately broken file exits 1, so the tool can fail.
  • Workflow guard tests (go test -count=1 -run 'Workflow|Pins|Gate' . ./internal/scaffold/cmd/pins-gate): pass, 85 tests.
  • Full root package (go test -count=1 .): three TestOracle* tests fail. They fail identically on an unmodified origin/main checkout in the same environment, so this change does not cause them.
  • No dispatch run was started. This PR's own runs exercise the PR concurrency group.

🤖 Generated with Claude Code

…ngs)

Port the civitai/civitai#6718/#6728 pattern:
- ci.yml: workflow_dispatch gets an 'only' choice input; every job but
  pins-vs-published (whose guard test forbids a job-level if:) gates on it.
  Concurrency groups push/PR by ref and dispatches by ref+only, cancel-in-progress.
- flake.yml, schema-drift.yml: ref-grouped concurrency with cancel-in-progress.

Docs-only skipping is deliberately not added: six ci.yml jobs are required
checks and Go tests read README.md, AGENTS.md, CLAUDE.md and claudedocs/**.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ZacxDev

ZacxDev commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

/audit-pr round 0 (requirements & deletion) of 415ef3c

Verdict: proceed to the checklist. There are no open premises.
Ledger: round 0 · requirements: 5 (unattributed: 0) · deletion candidates: 2

The ref-grouped concurrency on ci.yml has measured value: 39 of the last 400 runs started while an older run on the same ref was still going, about 484 runner-minutes of overlap. It also matches civitai/civitai#6728. schema-drift.yml has real volume. Leaving out a docs-only skip is right, given the 6 required checks.

D1 — `only` input + 9 job `if:` clauses in ci.yml: dispatched 3× in 400 runs; `gh run rerun --job` already covers re-running one job
D2 — flake.yml concurrency block: 1 run in 30 days, saves ~0 runner time

Dispositions (applied in the next push): D1 kept, because it is the ported org pattern and costs nothing when unused. D2 deleted.

🤖 Generated with Claude Code

ZacxDev and others added 2 commits October 23, 2026 20:30
flake.yml ran once in the last 30 days, so a cancel-superseded group saves
nothing there. ci.yml and schema-drift.yml keep theirs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Removes the workflow_dispatch `only` input and every job's `only` clause,
restoring each job's `if:` to main's. A narrowed dispatch writes skipped
check runs under the normal job names, and a skipped job satisfies a
required check, so a narrowed run at a pull request's head (or in the
webhook-outage recovery case) could pass required checks that never ran.

ci.yml keeps only the ref-grouped cancel-in-progress concurrency; a
dispatch gets its own `dispatch-` group per ref. schema-drift.yml keeps
its concurrency; flake.yml stays main's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@ZacxDev ZacxDev changed the title ci: dispatch 'only' selector + ref-grouped concurrency (runner savings) ci: cancel superseded runs per ref (ci, schema-drift) Oct 24, 2026
@ZacxDev

ZacxDev commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

/audit-pr round 1 (full correctness audit) of 1a2159b5, with fixes in 8b543b30

There is one 🔴 finding, one 🟡 and one 🟢.

  • 🔴 1 (fixed by removal): a dispatch with only=<x> at a PR head sha wrote skipped results under five of main's six required contexts, and a skipped result satisfies a required check. A red build-test could therefore turn green. In the documented webhook-drop recovery case, required checks that never ran would be satisfied. The only input is dropped entirely, because ci.yml was hand-dispatched 3 times in 400 runs and making it safe would need a lookup job plus guards. Every job's if: matches main.
  • 🟡 2 (moot): no tests pinned the only behaviour. The behaviour is removed.
  • 🟢 3 (moot): the unknown/empty only value handling is removed too.

Checked and found sound: the concurrency groups (refs/heads/main, refs/pull/N/merge, dispatch-…) are disjoint, so cancelling on main cannot leave a cancelled required check on a PR. pins-vs-published stays un-gated.

1. the `only` workflow_dispatch input and every `only` clause are removed; each job's `if:` is byte-identical to main
2. ci.yml keeps ref-grouped cancel-in-progress concurrency; manual dispatches get their own `dispatch-<ref>` group so they cannot cancel or be cancelled by push/PR runs
3. schema-drift.yml keeps its concurrency block; flake.yml is identical to main
4. actionlint clean on all three (negative control exits 1); workflow guard tests 85 pass

🤖 Generated with Claude Code

@ZacxDev

ZacxDev commented Oct 24, 2026

Copy link
Copy Markdown
Contributor Author

/audit-pr round 2 (delta audit of 1a2159b5..8b543b30)

There are no findings, so this round ends the ladder. Verdict: safe to merge.

  • git diff origin/main -- .github/workflows/ only adds concurrency blocks and comments. Every job if: is byte-identical to main, and no inputs.only or only: key remains anywhere in the repo.
  • The dispatch group ci-dispatch-<ref> cannot collide with push or PR groups, because ci-<ref> always continues with refs/. No other workflow shares the ci- or schema-drift- prefixes.
  • All six required contexts are unchanged ci.yml jobs.
  • Cancel-in-progress on push to main is acceptable: there is no workflow_run consumer, and releases run from tags.
  • actionlint exits 0, and a negative control is flagged. The workflow guard tests give 63 pass, 0 fail and 3 unrelated skips. The PR body's figure of 85 was not reproduced and probably used a wider test filter.

🤖 Generated with Claude Code

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