Skip to content

Conclusion job concurrency is static per workflow and cannot be customized #24037

@szabta89

Description

@szabta89

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:

  1. Preferred: apply concurrency.job-discriminator to the generated conclusion job as well.
  2. Alternatively: add an explicit frontmatter override for conclusion job concurrency.
  3. 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.

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions