Skip to content

Harden create_issue concurrency limits and remove dead copilot assignment queue code#27533

Merged
pelikhan merged 4 commits intomainfrom
copilot/fix-concurrency-issues-in-create-issue
Apr 21, 2026
Merged

Harden create_issue concurrency limits and remove dead copilot assignment queue code#27533
pelikhan merged 4 commits intomainfrom
copilot/fix-concurrency-issues-in-create-issue

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 21, 2026

create_issue had two concurrency hazards: dead module-level copilot assignment queue code and a max-limit TOCTOU window where concurrent invocations could both pass the limit check before incrementing. This updates the handler so max enforcement is synchronized with slot reservation before async work, and fully removes the dead queue path.

  • Max-count race fix (processedCount)

    • Moved max check + reservation into a single synchronous section before any await.
    • This prevents interleaving between check and increment across concurrent handler calls.
    • Group-by-day comment path still releases the reserved slot because no issue is created.
  • Dead copilot queue code removal (no backward compatibility)

    • Removed dead create_issue queue helpers and exports:
      • getIssuesToAssignCopilot()
      • resetIssuesToAssignCopilot()
    • Removed corresponding no-op/reset/output wiring in safe_output_handler_manager.cjs.
    • Updated tests to remove references to the deleted helpers and dropped queue-specific assertions.
  • Focused concurrency coverage

    • Added a concurrent max-limit test (max: 1) that invokes handleCreateIssue via Promise.all(...) through the group-by-day pre-check path and asserts only one create succeeds.
if (processedCount >= maxCount) {
  return { success: false, error: `Max count of ${maxCount} reached` };
}
processedCount++; // reserve before first await

[!WARNING]

Copilot AI and others added 2 commits April 21, 2026 10:58
Copilot AI changed the title [WIP] Fix concurrency safety issue in create_issue Harden create_issue concurrency limits and remove dead mutable assignment queue Apr 21, 2026
Copilot AI requested a review from pelikhan April 21, 2026 11:01
Comment thread actions/setup/js/create_issue.cjs Outdated
* Kept for backward-compatible tests and no-op downstream wiring.
* @returns {Array<string>} Always empty array
*/
function getIssuesToAssignCopilot() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot dead code, remove. No backward compat

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the dead compatibility code and dropped backward-compat shims in create_issue and dependent manager/test references in commit f5563aa.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 21, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh gh repo view --json owner,name --jq .owner.login &#43; &#34;/&#34; &#43; .name /usr/bin/git GOINSECURE GOMOD GOMODCACHE git stat�� --porcelain GOPROXY /opt/hostedtoolcache/node/24.14.1/x64/bin/node GOSUMDB GOWORK 64/bin/go node (http block)
    • Triggering command: /usr/bin/gh gh repo view owner/repo rev-�� --show-toplevel GOPROXY /usr/bin/git GOSUMDB GOWORK 64/bin/go git -C /tmp/gh-aw-test-runs/20260421-134103-29035/test-1690743168/.github/workflows remote /usr/bin/git prettier --check 64/bin/go git (http block)
    • Triggering command: /usr/bin/gh gh repo view owner/repo clon�� /tmp/TestParseDefaultBranchFromLsRemoteWithRealGitmaster_branch228478110/001 /tmp/TestParseDefaultBranchFromLsRemoteWithRealGitmaster_branch228478110/002/work /usr/bin/git -json GO111MODULE 64/bin/go git -C /tmp/gh-aw-test-runs/20260421-134103-29035/test-1474164258/.github/workflows config /usr/bin/infocmp remote.origin.urgit GOPROXY 64/bin/go infocmp (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE findmnt -t cgroup2 --noheadings 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq [.object.sha, .object.type] | @tsv --show-toplevel RB/L1Wa7eeJiw1neInitial commit /usr/bin/git itbranch_with_hygit itbranch_with_hyrev-parse e4b68e421d17c53b--show-toplevel git rev-�� --show-toplevel go /usr/bin/git ut1552649403/001node GO111MODULE 64/pkg/tool/linuinstall git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq [.object.sha, .object.type] | @tsv /tmp/TestGuardPolicyBlockedUsersCommaSeparatedCompiledOutput2731309918/001 rev-parse /usr/bin/gh --check **/*.cjs 64/bin/go gh run list --json /opt/hostedtoolcache/node/24.14.1/x64/bin/node --workflow nonexistent-workrev-parse --limit /opt/hostedtoolcache/node/24.14.1/x64/bin/node (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv ithout_min-integrity2365430029/001 GO111MODULE 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env -json GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv --show-toplevel 64/pkg/tool/linux_amd64/vet e/git-remote-https agentic-observabtr GO111MODULE ache/go/1.25.8/x: e/git-remote-https rev-�� om/github/gh-aw.git go /usr/bin/git -json GO111MODULE ache/go/1.25.8/x--show-toplevel /usr/bin/git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq [.object.sha, .object.type] | @tsv --show-toplevel git /usr/bin/git --end-of-optionsgit blob /bin/sh git rev-�� --show-toplevel /bin/sh /usr/bin/git git-upload-pack git l ache/node/24.14.--show-toplevel git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq [.object.sha, .object.type] | @tsv --bare l /usr/bin/git -json GO111MODULE 64/bin/go git -C /tmp/gh-aw-test-runs/20260421-134103-29035/test-1474164258/.github/workflows rev-parse /opt/hostedtoolcache/node/24.14.1/x64/bin/node &#34;prettier&#34; --chegit GOPROXY 64/bin/go node (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/infocmp -json GO111MODULE ache/go/1.25.8/x-b infocmp -1 xterm-color go /usr/bin/git 4103-29035/test-git GO111MODULE ache/node/24.14.--show-toplevel git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v9
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv GOSUMDB GOWORK 64/bin/go GOINSECURE GOMOD GOMODCACHE sh -c npx prettier --cGOINSECURE GOPROXY 64/bin/go GOSUMDB GOWORK 64/bin/go sh (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv prettier --check 64/bin/go --ignore-path .prettierignore 64/bin/go go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq [.object.sha, .object.type] | @tsv &#34;prettier&#34; --cheGOINSECURE sh 64/bin/go tierignore (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git 20/001/test-compgit GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv user.email test@example.com /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq [.object.sha, .object.type] | @tsv -bool -buildtags /opt/hostedtoolcache/node/24.14.1/x64/bin/node -errorsas -ifaceassert -nilfunc node /tmp�� /tmp/TestHashStability_SameInputSameOutput3104259260/001/stability-test.md -tests /usr/bin/git 73758822/001&#39; 73758822/001&#39; 64/bin/go git (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv --count st/suppress-warn-w $name) { hasDiscussionsEnabled } } README.md ion-test..token-init tions/node_modul/tmp/go-build4074235310/b001/_pkg_.a st/dist/workers/forks.js show�� --verify 319b56d3 de_modules/.bin/node token-test.txt (http block)
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq [.object.sha, .object.type] | @tsv d44f8315cabceace65700687e83e3f9c0d8323bf..full-mode-branch 319b56d3..HEAD tions/setup/node_modules/.bin/git README.md ion-test..token--c git git show�� --verify 319b56d3..HEAD n-dir/node token-test.txt ings.cjs ndor/bin/git git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq [.object.sha, .object.type] | @tsv /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq /usr/bin/git -json GO111MODULE 64/bin/go git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE 64/bin/go git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv k/gh-aw/gh-aw/.github/workflows/artifacts-summary.md config che/go-build/1e/1efcdb71e1a634f5730dd4f256396f648665568bc64849092d54587cb92abf9e-d remote.origin.urgit GOWORK 64/bin/go git -C /tmp/gh-aw-test-runs/20260421-134103-29035/test-2109714763/.github/workflows (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv /tmp/TestHashConsistency_GoAndJavaScript3200285120/001/test-empty-frontmatter.md--detach GOPROXY (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/1/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet env -json GO111MODULE e/git-upload-pack GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE flow.lock.yml GOINSECURE GOMOD GOMODCACHE go t-16�� sistency_GoAndJavaScript3200285120/001/test-empty-frontmatter.md GO111MODULE ache/node/24.14.1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12345/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json rsion=3f1f518-dirty e/git GOINSECURE GOMOD GOMODCACHE e/git (http block)
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/node/24.14.1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 d/gh-aw-wasm/main.go ache/go/1.25.8/x64/pkg/tool/linux_amd64/link s-in-body.md GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/link env -json GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/2/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet env ithub/workflows GO111MODULE 1/x64/bin/node GOINSECURE GOMOD GOMODCACHE 1/x64/bin/node (http block)
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE 1/x64/bin/node GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -has�� ithub/workflows/archie.md GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/3/artifacts --jq .artifacts[].name GO111MODULE 1/x64/bin/node GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet t-ha�� 999 GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/node/24.14.1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/4/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet env -json GO111MODULE ache/node/24.14.1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE ache/node/24.14.1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go t-28�� sistency_GoAndJavaScript3200285120/001/test-empty-frontmatter.md--detach GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/5/artifacts --jq .artifacts[].name GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet env FieldEnforcement1076742544/001 GO111MODULE e/git GOINSECURE GOMOD GOMODCACHE e/git (http block)
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE 1/x64/bin/node GOINSECURE GOMOD GOMODCACHE go t-ha�� ithub/workflows/approach-validator.md GO111MODULE /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path lint:cjs (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE P7KsbSroa4S9 env -json GO111MODULE 2d54587cb92abf9e-d GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE go env OnlyCompiledOutput1552649403/001 GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/contents/.github/workflows/shared/reporting.md
    • Triggering command: /tmp/go-build319376566/b403/cli.test /tmp/go-build319376566/b403/cli.test -test.testlogfile=/tmp/go-build319376566/b403/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE node /opt�� run lint:cjs 64/bin/go GOSUMDB GOWORK 64/bin/go npx (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v0.47.4
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v0.47.4 --jq [.object.sha, .object.type] | @tsv --show-toplevel go /usr/bin/git -json GO111MODULE ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel go /usr/bin/git 4103-29035/test-ls GO111MODULE /opt/hostedtoolc/tmp/gh-aw/aw-feature-branch.patch git (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go stlo�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go _bra�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env Gitmain_branch3273758822/001&#39; Gitmain_branch3273758822/001&#39; 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq [.object.sha, .object.type] | @tsv d/gh-aw-wasm GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env lGitmaster_brancremote.origin.url lGitmaster_branch228478110/001&#39; 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env Gitmaster_branch228478110/001&#39; Gitmaster_branch228478110/001&#39; 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq [.object.sha, .object.type] | @tsv -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE 1/x64/bin/node t-14�� bility_SameInputSameOutput3104259260/001/stability-test.md GO111MODULE 376566/b439/vet.cfg GOINSECURE GOMOD GOMODCACHE wasm -o gh-aw.opt.wasm &amp;&amp; \ mv gh-aw.opt.wasm gh-aw.wasm; \ AFTER=$(wc -c &lt; g (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOSUMDB GOWORK 64/bin/go node /opt�� prettier --check 64/bin/go --ignore-path .prettierignore 64/bin/go go (http block)
    • Triggering command: /usr/bin/gh gh workflow list --repo owner/repo --json name,path,state bject.type] | @tsv GOSUMDB GOWORK 64/bin/go infocmp -1 xterm-color sh /usr/bin/git npx prettier --cgit GOPROXY 64/bin/go git (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name with-tools.md GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE stat -f --format=%T /sys/fs/cgroup 64/bin/go GOSUMDB GOWORK 64/bin/go go (http block)
  • https://api.github.com/repos/test/repo
    • Triggering command: /usr/bin/gh gh api /repos/test/repo --jq .default_branch -bool -buildtags /usr/bin/gh -errorsas -ifaceassert -nilfunc gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq /usr/bin/git d/gh-aw-wasm GO111MODULE 64/bin/go git (http block)
  • invalid.example.invalid
    • Triggering command: /usr/lib/git-core/git-remote-https /usr/lib/git-core/git-remote-https origin https://invalid.example.invalid/nonexistent-repo.git git conf�� --local --get ode_modules/.bin/git cal/bin/git git /git git add . git tions/setup/node_modules/.bin/git -M main bin/git git (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Harden create_issue concurrency limits and remove dead mutable assignment queue Harden create_issue concurrency limits and remove dead copilot assignment queue code Apr 21, 2026
Copilot AI requested a review from pelikhan April 21, 2026 13:48
const issuesToAssignCopilot = getIssuesToAssignCopilot();
if (issuesToAssignCopilot.length > 0) {
const issuesToAssignStr = issuesToAssignCopilot.join(",");
core.setOutput("issues_to_assign_copilot", issuesToAssignStr);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot is this output used anywhere?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes — these assign_to_agent outputs are consumed downstream. They are wired by pkg/workflow/compiler_safe_outputs_job.go into safe_outputs job outputs and then referenced by workflow/error-notification paths (for example in pkg/workflow/notify_comment.go and generated lock workflows such as smoke-agent-public-approved.lock.yml, issue-monster.lock.yml, and workflow-generator.lock.yml).

@pelikhan pelikhan marked this pull request as ready for review April 21, 2026 14:00
Copilot AI review requested due to automatic review settings April 21, 2026 14:00
@github-actions github-actions Bot mentioned this pull request Apr 21, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 100/100

Excellent test quality

Metric Value
New/modified tests analyzed 1
✅ Design tests (behavioral contracts) 1 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 1 (100%)
Duplicate test clusters 0
Test inflation detected No (ratio ≈ 1.1:1)
🚨 Coding-guideline violations None

Test Classification Details

Test File Classification Notes
should respect max count limit under concurrent calls with group-by-day pre-check actions/setup/js/create_issue.test.cjs:270 ✅ Design Verifies concurrency-safe max-count enforcement via Promise.all

Notable Changes (Tests Removed)

This PR also removes two implementation tests that were testing internal state of the now-deleted copilot queue:

  • "getIssuesToAssignCopilot returns a copy, not the live reference" — correctly removed; tested internals of deleted code
  • "resetIssuesToAssignCopilot clears internal state but does not affect held snapshots" — correctly removed; same reason

Removing these is a quality improvement: they were testing implementation details of dead code.


New Test Analysis

should respect max count limit under concurrent calls with group-by-day pre-check

Design invariant enforced: Under concurrent invocations, the create_issue handler must enforce the max slot limit atomically — only one request may succeed when max: 1 and two requests race.

What would break if deleted? A race condition in the max-count reservation logic could allow two issues to be created simultaneously, bypassing the limit. This test would catch that regression.

Behavioral contract: ✅ Verifies observable outputs (result.success, result.error message, issues.create call count) — not internal function call order.

Edge/error coverage: ✅ Asserts the failure path (failures[0].error containing "Max count of 1 reached").

Mock usage: mockGithub.rest.issues.create mocks the GitHub API (external I/O) — legitimate.


Language Support

Tests analyzed:

  • 🟨 JavaScript (*.test.cjs): 1 new test (vitest)

No Go test files were added or modified.


Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). The PR replaces dead implementation-detail tests with a focused behavioral contract test that validates the concurrency fix end-to-end.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

References:

🧪 Test quality analysis by Test Quality Sentinel · ● 489.1K ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Test Quality Sentinel: 100/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). The single new test enforces the concurrency-safety behavioral contract of the create_issue max-count fix, and the PR correctly removes dead implementation-detail tests for the deleted copilot queue code.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens create_issue max-count enforcement under concurrency by reserving a slot before any async work, and removes the previously-dead “issues to assign copilot” queue/output plumbing.

Changes:

  • Move processedCount max check + reservation ahead of the group-by-day async pre-check to eliminate the TOCTOU window.
  • Remove the dead Copilot assignment queue helpers/exports from create_issue and remove corresponding wiring/outputs from the handler manager.
  • Update tests to drop queue assertions and add a concurrent max-limit test.
Show a summary per file
File Description
actions/setup/js/safe_output_handler_manager.cjs Removes create_issue Copilot queue reset/output wiring.
actions/setup/js/create_issue.cjs Removes dead queue API; synchronizes max-count check with slot reservation; releases slot on group-by-day comment path.
actions/setup/js/create_issue.test.cjs Removes deleted helper usage; adds concurrent max-limit coverage.
actions/setup/js/create_discussion_fallback.test.cjs Removes references to deleted create_issue reset helper.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 2

@@ -1224,16 +1218,6 @@ async function main() {
// Export processed count for consistency with project handler
core.setOutput("processed_count", successCount);

Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workflow output issues_to_assign_copilot is no longer set here. There are still repo workflows referencing steps.process_safe_outputs.outputs.issues_to_assign_copilot (e.g. .github/workflows/*lock.yml), so leaving the output undefined may cause those steps to silently skip (or behave inconsistently across runners). Consider either continuing to set issues_to_assign_copilot to an empty string for compatibility, or updating/removing the downstream workflow steps in the same PR to match the breaking change.

Suggested change
// Preserve the legacy workflow output contract for downstream steps that still
// reference issues_to_assign_copilot, even though this handler no longer populates it.
core.setOutput("issues_to_assign_copilot", "");

Copilot uses AI. Check for mistakes.
@@ -554,6 +526,9 @@ async function main(config = {}) {
core.info(`Group-by-day: found open issue #${todayIssue.number} created today (${today}) — posting new content as a comment`);
const comment = await addIssueComment(githubClient, repoParts.owner, repoParts.repo, todayIssue.number, body);
core.info(`Posted content as comment ${comment.html_url} on issue #${todayIssue.number}`);
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When group-by-day finds an existing issue and posts a comment, the handler returns success without recording the temporaryId -> existing issue mapping in temporaryIdMap. If a caller provides an explicit temporary_id and later messages reference it, those references will remain unresolved even though the content was associated with todayIssue. Consider storing a mapping to todayIssue.number (and repo) before returning from the grouped path.

Suggested change
core.info(`Posted content as comment ${comment.html_url} on issue #${todayIssue.number}`);
core.info(`Posted content as comment ${comment.html_url} on issue #${todayIssue.number}`);
if (temporaryId) {
temporaryIdMap.set(normalizeTemporaryId(temporaryId), {
owner: repoParts.owner,
repo: repoParts.repo,
issue_number: todayIssue.number,
});
}

Copilot uses AI. Check for mistakes.
Copilot AI requested a review from pelikhan April 21, 2026 14:21
@pelikhan pelikhan merged commit b1dcb4a into main Apr 21, 2026
110 checks passed
@pelikhan pelikhan deleted the copilot/fix-concurrency-issues-in-create-issue branch April 21, 2026 15:04
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.

[concurrency] Concurrency Safety Issue in create_issue - processedCount TOCTOU and dead module-level mutable state

3 participants