Summary
gh-aw currently generates a static concurrency group for the compiler-generated conclusion job:
gh-aw-conclusion-<workflow-id>
This is not configurable from frontmatter, and it causes incorrect behavior in concurrent issue-driven workflows. When several runs of the same workflow happen at nearly the same time, GitHub Actions concurrency allows one running and one pending job per group, and later requests can cancel older pending conclusion jobs with messages like:
Canceling since a higher priority waiting request for gh-aw-conclusion-<workflow-id> exists.
This means the generated conclusion job can be dropped even though the rest of the workflow completed successfully.
Observed behavior
In an issue-triggered gh-aw workflow, multiple runs for different issues can complete activation, agent, detection, and safe_outputs, but the generated conclusion job is serialized across all runs of that workflow by a static group.
Because the group is static, concurrent runs for different issues compete for the same conclusion slot. If enough runs overlap, older pending conclusion jobs are cancelled by GitHub Actions queue behavior.
Observed example:
https://github.com/githubnext/gh-aw-security/actions/runs/23854981154
In that run, the main workflow work completed successfully, but the conclusion job was cancelled with:
Canceling since a higher priority waiting request for gh-aw-conclusion-pentest-xpia-victim-triage exists.
Why this is a problem
The docs describe the conclusion job concurrency as preventing collisions when multiple agents run the same workflow concurrently, and say queued conclusion runs complete in order rather than being discarded.
In practice, because the generated group is static per workflow, GitHub's concurrency semantics mean this is not true under higher fan-out. The static group causes unrelated runs for different issues or inputs to interfere with each other.
This is especially problematic for:
- issue-triggered workflows
- discussion-triggered workflows
- fan-out patterns where many runs of the same compiled workflow occur close together
- workflows where
conclusion is responsible for reporting, cleanup, or final status propagation
Current workaround
The only effective workaround I found is patching the generated lock file after compilation so the conclusion job group includes a per-run discriminator, for example:
conclusion:
concurrency:
group: "gh-aw-conclusion-pentest-xpia-victim-triage-${{ github.event.issue.number || github.run_id }}"
cancel-in-progress: false
This fixes the cancellation behavior, but it is not viable because the change is lost on recompile.
Root cause
The compiler currently hardcodes the conclusion concurrency group from WorkflowID alone.
There is no frontmatter field to influence this group:
concurrency.job-discriminator only applies to compiler-generated agent and output job groups
safe-outputs.concurrency-group only applies to the safe_outputs job
conclusion concurrency has no override or discriminator support
Verified in source
Current compiler logic in pkg/workflow/notify_comment.go builds the group as:
group := "gh-aw-conclusion-" + data.WorkflowID
The corresponding test in pkg/workflow/notify_comment_test.go asserts the same static pattern:
expectedGroup: "gh-aw-conclusion-my-workflow"
The docs also state that conclusion job concurrency is automatic and not configurable.
Expected solution
One of these should be implemented:
- Preferred: apply
concurrency.job-discriminator to the generated conclusion job as well.
- Alternatively: add an explicit frontmatter override for conclusion job concurrency.
- At minimum: change the compiler-generated default for
conclusion to include a run-specific discriminator for triggers where multiple instances of the same workflow can run concurrently.
Suggested behavior
A good default would be something like:
group: "gh-aw-conclusion-<workflow-id>-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}"
Or, if keeping defaults stable is important, allow users to opt in via frontmatter using an override or discriminator field.
Additional changes needed
Please update:
- compiler implementation for conclusion job concurrency generation
- schema and frontmatter docs
- unit tests covering conclusion job concurrency
- reference docs that currently state the conclusion group prevents collisions automatically and that queued runs are not discarded
Impact
Without this fix, concurrent runs of the same gh-aw workflow can silently lose their conclusion job, which breaks final reporting and cleanup semantics and makes generated workflow behavior unreliable under load.
Summary
gh-aw currently generates a static concurrency group for the compiler-generated
conclusionjob:gh-aw-conclusion-<workflow-id>This is not configurable from frontmatter, and it causes incorrect behavior in concurrent issue-driven workflows. When several runs of the same workflow happen at nearly the same time, GitHub Actions concurrency allows one running and one pending job per group, and later requests can cancel older pending
conclusionjobs with messages like:Canceling since a higher priority waiting request for gh-aw-conclusion-<workflow-id> exists.This means the generated
conclusionjob can be dropped even though the rest of the workflow completed successfully.Observed behavior
In an issue-triggered gh-aw workflow, multiple runs for different issues can complete
activation,agent,detection, andsafe_outputs, but the generatedconclusionjob is serialized across all runs of that workflow by a static group.Because the group is static, concurrent runs for different issues compete for the same
conclusionslot. If enough runs overlap, older pending conclusion jobs are cancelled by GitHub Actions queue behavior.Observed example:
https://github.com/githubnext/gh-aw-security/actions/runs/23854981154
In that run, the main workflow work completed successfully, but the
conclusionjob was cancelled with:Canceling since a higher priority waiting request for gh-aw-conclusion-pentest-xpia-victim-triage exists.Why this is a problem
The docs describe the
conclusionjob concurrency as preventing collisions when multiple agents run the same workflow concurrently, and say queued conclusion runs complete in order rather than being discarded.In practice, because the generated group is static per workflow, GitHub's concurrency semantics mean this is not true under higher fan-out. The static group causes unrelated runs for different issues or inputs to interfere with each other.
This is especially problematic for:
conclusionis responsible for reporting, cleanup, or final status propagationCurrent workaround
The only effective workaround I found is patching the generated lock file after compilation so the
conclusionjob group includes a per-run discriminator, for example:This fixes the cancellation behavior, but it is not viable because the change is lost on recompile.
Root cause
The compiler currently hardcodes the conclusion concurrency group from
WorkflowIDalone.There is no frontmatter field to influence this group:
concurrency.job-discriminatoronly applies to compiler-generatedagentandoutputjob groupssafe-outputs.concurrency-grouponly applies to thesafe_outputsjobconclusionconcurrency has no override or discriminator supportVerified in source
Current compiler logic in
pkg/workflow/notify_comment.gobuilds the group as:The corresponding test in
pkg/workflow/notify_comment_test.goasserts the same static pattern:expectedGroup: "gh-aw-conclusion-my-workflow"The docs also state that conclusion job concurrency is automatic and not configurable.
Expected solution
One of these should be implemented:
concurrency.job-discriminatorto the generatedconclusionjob as well.conclusionto include a run-specific discriminator for triggers where multiple instances of the same workflow can run concurrently.Suggested behavior
A good default would be something like:
Or, if keeping defaults stable is important, allow users to opt in via frontmatter using an override or discriminator field.
Additional changes needed
Please update:
Impact
Without this fix, concurrent runs of the same gh-aw workflow can silently lose their
conclusionjob, which breaks final reporting and cleanup semantics and makes generated workflow behavior unreliable under load.