Skip to content

ci: give the 102 push workflows a dispatch-safe concurrency group - #870

Open
gHashTag wants to merge 3 commits into
mainfrom
ci/concurrency-groups
Open

gHashTag wants to merge 3 commits into
mainfrom
ci/concurrency-groups

Conversation

@gHashTag

@gHashTag gHashTag commented Oct 4, 2026 •

Copy link
Copy Markdown
Owner

Closes #869. Supersedes #647, regenerated on current main instead of rebased.

Edited 2026-10-04T19:33Z: a second commit (066bfa2) adds a gate that keeps every push workflow grouped, and this PR's own runs now show the push and pull_request behaviour. See "The gate" and "Seen on this PR". The first commit is unchanged.

Edited 2026-10-04T21:25Z: a third commit (3032785) gives bench007-probe-ax7203 and trinity-identity-gate the same block, and makes DISPATCH_CANCELS a failure. See "Third commit". It stands alone, so reverting it restores the two old groups and the note.

What

Adds one top-level block to each of the 102 workflows that run on push to main and have no group:

# A newer push or PR commit replaces this file's pending run instead of
# queueing behind it; a dispatch is never cancelled (gHashTag/trinity-fpga#869).
concurrency:
  group: ${{ github.workflow_ref }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.event_name }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
event effect
push One run active and one pending per file and branch. A newer commit replaces the pending run. The active run is never cancelled, so main still gets a result for the commit that started.
pull_request A new commit cancels the old commit's run.
workflow_dispatch Each run gets its own group, so it is never cancelled and never cancels anything.
schedule A new tick replaces only an older tick that is still pending.

Measured (#869)

  • The burst: eight merges between 18:38:47Z and 18:42:09Z on 2026-10-04 started 220 push runs on main across 66 workflows.
  • The wait: jobs waited about 25 minutes for a runner.
  • The cause: 102 of the 104 push-to-main workflows had no group.
  • Estimate: at most 97 of those 220 runs would have run with this change, 56% fewer. This assumes every workflow's first run was still active when the burst ended. That held tonight: the burst lasted 3.5 minutes and the wait was about 25. It was not measured on a real burst.

How it differs from #647

#647's key was ${{ github.workflow }}-${{ github.ref }} with cancel-in-progress: true. On today's tree that key has three problems:

  1. A push could cancel a dispatch. 85 of the 102 workflows also have workflow_dispatch. A push to main would have cancelled a manual run in progress on main, because both are in the group <name>-refs/heads/main.
  2. Dispatches cancelled each other. A second dispatch would have cancelled the first, even with different inputs. Seed sweeps and A/B pairs (ci(fpga): audit the 31 workflows that pass --placer sa against today's image #862, ci: 7 workflows build a chipdb with no cache #846) are dispatched in batches.
  3. Two files share a name. conformance-golden-selftests.yml and conformance-selftest.yml are both named "Conformance golden self-tests". With github.workflow in the key they would share one group, and in a burst one file's pending run would replace the other's. github.workflow_ref names the file, so it cannot collide.

#647 is also 766 commits behind and conflicts with main in two files. I have not closed it; that is the owner's call.

The gate (second commit)

Nothing in the first commit stops the next new workflow from arriving without a group. tools/check_concurrency_groups.py does, in a new concurrency-gate.yml (push to main and pull_request, on .github/workflows/** and its own two files). It reads each workflow with PyYAML's composer and fails on three things (four since the third commit):

class what
UNGROUPED runs on a push to main and has no top-level group (a job-level group does not count)
BAD_REUSABLE workflow_call with a top-level group; a called workflow reads its caller's github context, so the group is the caller's own
SHARED_KEY two files whose groups are the same text once each file's path and name: are put in; every file with a group is compared, not only push ones
DISPATCH_CANCELS (third commit; a note before it) dispatchable, and the group has no github.run_id, so a push replaces or cancels a manual run

"Push to main" follows GitHub's filter rules: branches: in order with !, branches-ignore:, tags-only filters, and ? / + as repeats of the character before them. Exit 0 clean, 1 defect, 2 cannot tell (no PyYAML, unreadable YAML, a duplicate or merge key, no workflows).

Checked before pushing:

  • This branch: 123 workflows read, 105 on push to main (the gate itself is the 105th), 105 grouped, rc 0.
  • Negative control, main at 57de4a1: 102 UNGROUPED, rc 1.
  • Independent reader: a line-based reader of the same rules, written first for the measurement in ci: a merge burst queues every superseded commit's gates (220 runs from 8 merges); add dispatch-safe concurrency groups #869, gives the same class to every file: 122/122 on main and 122/122 on this branch.
  • Planted cases: tools/test_check_concurrency_groups.py, 57 of 57.
  • Mutation run: 29 of 29 mutants of the checker turn that test red. One more mutant, * crossing /, cannot be caught: only main is asked about, and it has no /.
  • research/audit_workflow_paths.py: 0 dead paths: entries, 0 scripts run but not watched.
  • Gates can fail: registered in tools/check_gates_can_fail.py with a planted on: push workflow and no group. Run locally, the clean tree gives rc 0, the planted workflow gives rc 1, and the file is removed afterwards. MIN_TESTABLE goes from 11 to 12, as the comment in gates-can-fail.yml asks for every gate added to the harness.

Third commit: the last two dispatch-cancelling groups

When the first commit was made, bench007-probe-ax7203 and trinity-identity-gate already had groups, <name>-${{ github.ref }} with cancel-in-progress: true. A push to main shares that group with a dispatch on main, so the push cancels the dispatch. For the BENCH-007 probe, that dispatch is a bitstream build of up to four hours (timeout-minutes: 240). The second commit left both alone and called them the owner's call. Neither commit that set those groups (9947512, b71a144) gives a reason, and #798 does not mention one either, so I changed them. If one of them is deliberate, revert 3032785 alone.

gate result
tree at 066bfa2 old gate NOTE DISPATCH_CANCELS 2, rc 0
tree at 066bfa2 new gate FAIL DISPATCH_CANCELS 2, rc 1 (negative control)
this branch new gate 105 of 105 grouped, rc 0
planted cases 59 of 59. Two cases flip to rc 1; two are added: the failure names the class, and the same group without workflow_dispatch passes

The 29-mutant run above was done on the second commit's checker. It was not repeated for this one.

Seen on this PR

  • The expressions are accepted. None of the 60 runs on the first commit (b1894fb) ended in a workflow-file or startup error. lut-report.yml, one of the 102 edited files, ran to success (run 37227380125).
  • pull_request: pushing the second commit cancelled all 37 of the first commit's pull_request runs that had not finished, at 19:30Z.
  • push: the 16 push runs on this branch from the first commit were not cancelled. Each of the 10 workflows that started a push run for the second commit shows it as pending behind the first commit's run, which is one active and one pending per group.

Checked (first commit)

Not measured

Refs #851 #865

🤖 Generated with Claude Code

Eight merges in 3m22s on 2026-10-04 started 220 push runs on main across
66 workflows, and jobs waited ~25 min for a runner (#869). 102 of the 104
workflows that run on push to main had no concurrency group, so nothing
superseded anything.

Each of them now has, at top level:

  concurrency:
    group: ${{ github.workflow_ref }}-${{ github.event_name == 'workflow_dispatch' && github.run_id || github.event_name }}
    cancel-in-progress: ${{ github.event_name == 'pull_request' }}

- push: one run active and one pending per file and branch; a newer
  commit replaces the pending run, and the active run is not cancelled.
- pull_request: a new commit cancels the old commit's run.
- workflow_dispatch: a group per run, so a push never cancels a manual
  run and two dispatches with different inputs never cancel each other.
  85 of the 102 can be dispatched; #647's group (workflow + ref,
  cancel-in-progress always) would have done both.
- The key is workflow_ref (the file), not github.workflow (the name):
  conformance-golden-selftests.yml and conformance-selftest.yml are both
  named "Conformance golden self-tests" and would have shared a group.

Skipped: 2 workflows that already have a group, 18 with no push trigger,
0 reusable workflows. 102 files, 6 lines each, 0 deletions; every edited
file re-parses with the block at top level and no job carrying one.

Refs #869 #647 #851

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The first commit of this branch gave the 102 ungrouped push workflows a
concurrency group (2/104 -> 104/104). Nothing kept the next workflow from
arriving without one. This adds the gate.

tools/check_concurrency_groups.py reads every workflow with PyYAML's
composer, as the runner reads it, and fails on three things:

  UNGROUPED     runs on a push to main, no top-level group
  BAD_REUSABLE  workflow_call with a top-level group: a called workflow
                reads its caller's github context, so the group is the
                caller's own
  SHARED_KEY    two files whose groups are the same text once each file's
                path and name are put in (two files here share a name:)

A dispatchable group without github.run_id is printed as a note, not a
failure: bench007-probe-ax7203 and trinity-identity-gate are built that
way. Push-to-main follows GitHub's filter rules (branches in order with
`!`, branches-ignore, tags-only, `?` and `+` as repeats). Exit 0 clean,
1 defect, 2 cannot tell (no PyYAML, unreadable YAML, duplicate or merge
key, no workflows).

Measured before committing:
  - this branch: 123 read, 105 on push to main, 105 grouped, rc 0
  - main (57de4a1): 102 UNGROUPED, rc 1 -- the negative control
  - per-file agreement with an independent line-based reader of the
    same rules: 122/122 on main and 122/122 on this branch
  - tools/test_check_concurrency_groups.py: 57 of 57 planted cases
  - mutation run on the checker: 29/29 mutants turn the test red; one
    more (`*` crossing `/`) is equivalent, since only `main` is asked
    about and it has no `/`
  - research/audit_workflow_paths.py: 0 dead paths, 0 unwatched scripts
  - the gates-can-fail case: clean rc 0, planted workflow rc 1

Registered in tools/check_gates_can_fail.py; MIN_TESTABLE 11 -> 12, as
that workflow's own comment asks of every gate added to the harness.

Refs #869

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

X Brain Health Check

Score: 100.0/100
Status: 🟢 HEALTHY
Threshold: 80/100

X Brain is above merge threshold

@gHashTag

gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner Author

The six red checks on this PR are all pre-existing failures on main

This PR changes concurrency groups only. The six failing checks, as of run time 2026-10-04 19:52Z, have these causes:

check runs cause fixed by
Document references (doc-refs) 1 main has failed since #510 merged (57de4a1, run 37225448197) #872
Orphaned artefacts 2 the same, run 37225448159 #872
gates-can-fail 2 this PR edits workflows, so the gate tests every checker, and it reports doc-refs and orphan-artefacts as untestable on a red tree #872, then a rerun here
Build Conscious Image 1 Dockerfile.conscious copies synth.sh and synth_conscious.sh, which were deleted in March. 0 of 6 runs ever passed. It runs here only because this PR touches fpga-docker.yml #874 (the maintainer chooses the fix)

93 checks pass, 3 are pending, and 4 are skipped.

Order: once #872 is on main, I will merge main into this branch and rerun, so the first three rows should turn green. The fourth will stay red until #874 is decided.

🤖 Generated with Claude Code

bench007-probe-ax7203.yml and trinity-identity-gate.yml kept their own
groups, <name>-<ref> with cancel-in-progress: true. A push to main shared
that group with a dispatch on main and cancelled it. For the BENCH-007 probe
that is a bitstream build of up to four hours (timeout-minutes: 240). Neither
commit that set those groups (9947512, b71a144) gives a reason, and #798
does not mention one.

Both now carry the block the other 103 push workflows have. With that,
DISPATCH_CANCELS moves from a note to a failure in the gate, so the count
stays at zero:

  before (066bfa2 tree): NOTE DISPATCH_CANCELS 2, rc 0
  new gate on that tree:   FAIL DISPATCH_CANCELS 2, rc 1
  new gate on this tree:   105 of 105 grouped, rc 0
  planted cases:           59 of 59 (two cases flipped to rc 1, two added)

This commit stands alone. Reverting it restores both old groups and the
note.

Refs #869

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

🚨 CRITICAL: Brain Health Below Threshold

The brain health CI gate has failed. This PR cannot be merged until:

  1. All brain region unit tests pass
  2. Integration tests pass
  3. Stress test score >= 270/300
  4. Brain health score >= 80/100

Please review the failed job logs and fix the issues.

@github-actions

github-actions Bot commented Oct 4, 2026

Copy link
Copy Markdown

🧪 Brain Stress Test Results

Score: not measured (no stress test prints a Score: line)
Status: 🟢 PASS
Threshold: 270/300

X Stress test passed

@gHashTag

gHashTag commented Oct 4, 2026

Copy link
Copy Markdown
Owner Author

The "🚨 CRITICAL: Brain Health Below Threshold" comment above (21:10:18Z) is a false alarm, and this PR's concurrency change is what triggers it.

  • Run 37228527559 was cancelled at 20:58:18Z by this PR's own cancel-in-progress group when 3032785 was pushed. Every brain job that had finished was green; the stress test was the job that got cancelled.
  • brain-health-report runs on if: always(), requires every need to be success, and a cancelled need is not success. So it failed and posted the comment.
  • The run for 3032785, 37234155119, is green in every job, the report included.

main's brain-ci.yml has no concurrency: block, so today only a manual cancel can trigger this. After this PR, every push made during a brain-ci run would. #882 (issue #881) changes the report to if: ${{ !cancelled() }}. Its merge with this branch is clean (git merge-tree), and it should go in before this PR.

🤖 Generated with Claude Code

@tri-claw

tri-claw Bot commented Oct 10, 2026

Copy link
Copy Markdown

Summary by t27-bees

This PR adds a standardized concurrency block to 102 workflow files that run on push to main but lacked concurrency control, preventing burst merges from queueing hundreds of runs. It also adds a gate workflow and checker script to enforce that future workflows include proper concurrency groups.

Worth a look

  • .github/workflows/bench007-probe-ax7203.yml (lines 33–42): Replaces a custom group bench007-probe-${{ github.ref }} with cancel-in-progress: true with the new standard group. The old group allowed a push to main to cancel a long-running dispatched bitstream build (up to 4 hours). The new group fixes this, but verify that the previous behavior (cancelling on any push) was not relied upon for resource management.

  • .github/workflows/trinity-identity-gate.yml (shown as +6 -2): Similarly replaces an existing custom concurrency group. The diff is not shown in the provided output; confirm the old group did not have intentional semantics (e.g., cross-workflow coordination) that the new per-file group loses.

  • tools/check_concurrency_groups.py (new, 358 lines): The gate depends entirely on this script. If it has false positives (flags valid workflows) or false negatives (misses ungrouped workflows), the gate will either block legitimate PRs or let ungrouped workflows through. The test file tools/test_check_concurrency_groups.py should be audited for coverage of edge cases (reusable workflows, matrix jobs, workflows with only schedule or workflow_dispatch triggers).

  • .github/workflows/concurrency-gate.yml (lines 38–47): The gate workflow applies the same concurrency pattern to itself. If the checker script fails to install PyYAML (the pip install --break-system-packages step), the gate will error on every run, blocking all workflow changes. Consider pinning PyYAML in a requirements file or using a cached action.

  • .github/workflows/gates-can-fail.yml (lines 66–75): MIN_TESTABLE bumped from 11 to 12 to include the new concurrency checker. If check_concurrency_groups.py has a bug that causes it to fail on the current tree, the gate-ratchet will fail and block merges until fixed or MIN_TESTABLE is reverted.


Read: 108 files, +1250 -8, the whole diff up to 60000 characters (the rest was not read). Head a4d4508. Model: openai-compatible/nvidia/nemotron-3-ultra-550b-a55b. Commands: @t27-bees review | summary | help | pause | resume. Free for every repository.

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.

ci: a merge burst queues every superseded commit's gates (220 runs from 8 merges); add dispatch-safe concurrency groups

1 participant