Skip to content

Add retry with jitter to create_issue safe-output handler#26056

Merged
pelikhan merged 5 commits intomainfrom
copilot/deep-report-add-concurrency-throttling
Apr 13, 2026
Merged

Add retry with jitter to create_issue safe-output handler#26056
pelikhan merged 5 commits intomainfrom
copilot/deep-report-add-concurrency-throttling

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 13, 2026

create_issue fails with HTTP 403 when multiple daily workflows complete simultaneously and burst the rate limit within a ~3-minute window. Recurring pattern (3 incidents in 11 days), sole cause of "Degraded" safe-output health.

Changes

  • error_recovery.cjs: Add jitterMs option to withRetry (default 100ms). When set, adds Math.floor(Math.random() * jitterMs) to each retry delay to desynchronize concurrent callers.

  • create_issue.cjs: Wrap both issues.create calls (main + parent) with withRetry:

    const { data: issue } = await withRetry(
      () => githubClient.rest.issues.create({ owner, repo, title, body, labels, assignees }),
      { initialDelayMs: 15000, maxDelayMs: 45000, jitterMs: 10000 },
      `create_issue in ${qualifiedItemRepo}`,
    );

    Non-retryable errors (e.g. "Issues disabled") still fail immediately via isTransientError check.

  • Tests: Jitter unit tests in error_recovery.test.cjs (mocked Math.random); retry integration tests in create_issue.test.cjs (fake timers). Updated one existing assertion from exact match to toContain since withRetry now wraps non-retryable errors with enhanced context.

…try logic

- Add jitterMs config option to withRetry in error_recovery.cjs (defaults to 0)
- Apply random jitter to each retry delay to prevent thundering herd
- Wrap main issues.create call in create_issue.cjs with withRetry (15-45s backoff, 10s jitter)
- Wrap parent issues.create call in create_issue.cjs with withRetry (same config)
- Add tests for jitter behavior in error_recovery.test.cjs
- Add retry tests with fake timers in create_issue.test.cjs
- Update error assertion to handle enhanced error from withRetry

Fixes #26067

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/54f4ec0f-3333-4b98-93ca-b11439da48d0

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Add concurrency throttling to safe-output create_issue Add retry with jitter to create_issue safe-output handler Apr 13, 2026
Copilot AI requested a review from pelikhan April 13, 2026 15:51
@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot default jitter is 100ms

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/4e674a3b-b2a0-405d-802f-31d302024908

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 13, 2026

@copilot default jitter is 100ms

Done in 733aae4 — changed DEFAULT_RETRY_CONFIG.jitterMs from 0 to 100.

@pelikhan pelikhan marked this pull request as ready for review April 13, 2026 16:15
Copilot AI review requested due to automatic review settings April 13, 2026 16:15
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

Adds jittered retry behavior around create_issue GitHub API calls to reduce synchronized bursts that trigger secondary rate limits (HTTP 403) when multiple workflows complete at the same time.

Changes:

  • Extended withRetry to support a jitterMs option and updated default retry config.
  • Wrapped githubClient.rest.issues.create calls in create_issue (main + parent issue creation) with withRetry using long delays + jitter.
  • Added/updated tests for jitter behavior and create-issue retry behavior (using fake timers), and relaxed one error-string assertion.
Show a summary per file
File Description
actions/setup/js/error_recovery.cjs Adds jitter to retry delays and updates default retry config.
actions/setup/js/error_recovery.test.cjs Adds unit coverage for jitter behavior and updates default-config assertions.
actions/setup/js/create_issue.cjs Wraps issue creation calls with withRetry using jittered backoff.
actions/setup/js/create_issue.test.cjs Adds integration-style retry tests for rate-limit errors and relaxes an assertion due to enhanced error wrapping.

Copilot's findings

Tip

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

Comments suppressed due to low confidence (2)

actions/setup/js/error_recovery.cjs:103

  • delayWithJitter can exceed maxDelayMs because the cap is applied before adding jitter (e.g., delay==maxDelayMs, jitter>0). If maxDelayMs is intended to be a hard upper bound on sleep time, cap after adding jitter (or rename/clarify the semantics).
        const jitter = fullConfig.jitterMs > 0 ? Math.floor(Math.random() * fullConfig.jitterMs) : 0;
        const delayWithJitter = delay + jitter;
        core.info(`Retry attempt ${attempt}/${fullConfig.maxRetries} for ${operationName} after ${delayWithJitter}ms delay`);
        await sleep(delayWithJitter);

actions/setup/js/create_issue.cjs:609

  • withRetry retries a non-idempotent issues.create call on any isTransientError match (timeouts/network errors included). If the request actually succeeded but the client timed out, a retry can create duplicate issues. Consider narrowing shouldRetry here to rate-limit/abuse/5xx cases, or adding an idempotency check (e.g., search by temporary_id marker) before retrying.
      const { data: issue } = await withRetry(
        () =>
          githubClient.rest.issues.create({
            owner: repoParts.owner,
            repo: repoParts.repo,
            title,
            body,
            labels,
            assignees,
          }),
        { initialDelayMs: 15000, maxDelayMs: 45000, jitterMs: 10000 },
        `create_issue in ${qualifiedItemRepo}`
      );
  • Files reviewed: 4/4 changed files
  • Comments generated: 3

* @property {number} initialDelayMs - Initial delay in milliseconds (default: 1000)
* @property {number} maxDelayMs - Maximum delay in milliseconds (default: 10000)
* @property {number} backoffMultiplier - Backoff multiplier for exponential backoff (default: 2)
* @property {number} jitterMs - Maximum random jitter in milliseconds added to each retry delay (default: 0)
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The JSDoc says jitterMs defaults to 0, but DEFAULT_RETRY_CONFIG sets jitterMs: 100. Please align the documentation with the actual default (or change the default) so callers know whether jitter is enabled when they omit the option.

This issue also appears on line 100 of the same file.

Suggested change
* @property {number} jitterMs - Maximum random jitter in milliseconds added to each retry delay (default: 0)
* @property {number} jitterMs - Maximum random jitter in milliseconds added to each retry delay (default: 100)

Copilot uses AI. Check for mistakes.
Comment on lines +171 to 185
const { data: parentIssue } = await withRetry(
() =>
githubClient.rest.issues.create({
owner,
repo,
title: template.title,
body: template.body,
labels: labels,
}),
{ initialDelayMs: 15000, maxDelayMs: 45000, jitterMs: 10000 },
`create_parent_issue for group ${groupId}`
);

core.info(`Created new parent issue #${parentIssue.number}: ${parentIssue.html_url}`);
return parentIssue.number;
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

Same non-idempotency concern as the main issue creation: retrying issues.create for the parent issue on network/timeout errors can create multiple parent issues for the same group. Consider narrowing shouldRetry for this call or adding an idempotency guard (e.g., re-search for an existing parent marker before retrying).

This issue also appears on line 597 of the same file.

Suggested change
const { data: parentIssue } = await withRetry(
() =>
githubClient.rest.issues.create({
owner,
repo,
title: template.title,
body: template.body,
labels: labels,
}),
{ initialDelayMs: 15000, maxDelayMs: 45000, jitterMs: 10000 },
`create_parent_issue for group ${groupId}`
);
core.info(`Created new parent issue #${parentIssue.number}: ${parentIssue.html_url}`);
return parentIssue.number;
const parentIssueNumber = await withRetry(
async () => {
const existingParentOnRetry = await searchForExistingParent(githubClient, owner, repo, markerComment);
if (existingParentOnRetry) {
core.info(`Found existing parent issue for group ${groupId} during retry; reusing #${existingParentOnRetry}`);
return existingParentOnRetry;
}
const { data: parentIssue } = await githubClient.rest.issues.create({
owner,
repo,
title: template.title,
body: template.body,
labels: labels,
});
core.info(`Created new parent issue #${parentIssue.number}: ${parentIssue.html_url}`);
return parentIssue.number;
},
{ initialDelayMs: 15000, maxDelayMs: 45000, jitterMs: 10000 },
`create_parent_issue for group ${groupId}`
);
return parentIssueNumber;

Copilot uses AI. Check for mistakes.
Comment on lines +680 to +722
it("should retry issue creation on transient rate limit error and succeed", async () => {
mockGithub.rest.issues.create = vi
.fn()
.mockRejectedValueOnce(new Error("Secondary rate limit hit"))
.mockResolvedValue({
data: {
number: 456,
html_url: "https://github.com/owner/repo/issues/456",
title: "Retried Issue",
},
});

const handler = await main({});
const resultPromise = handler({
title: "Retried Issue",
body: "Test body",
});

await vi.runAllTimersAsync();
const result = await resultPromise;

expect(result.success).toBe(true);
expect(result.number).toBe(456);
expect(mockGithub.rest.issues.create).toHaveBeenCalledTimes(2);
});

it("should fail after exhausting retries on persistent rate limit error", async () => {
mockGithub.rest.issues.create = vi.fn().mockRejectedValue(new Error("Secondary rate limit hit"));

const handler = await main({});
const resultPromise = handler({
title: "Failing Issue",
body: "Test body",
});

await vi.runAllTimersAsync();
const result = await resultPromise;

expect(result.success).toBe(false);
expect(result.error).toBeDefined();
// 1 initial + 3 retries = 4 calls
expect(mockGithub.rest.issues.create).toHaveBeenCalledTimes(4);
});
Copy link

Copilot AI Apr 13, 2026

Choose a reason for hiding this comment

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

The new retry tests only cover the success/failure paths, but don’t assert that the retry delays respect the configured bounds when jitter is enabled. Consider adding an assertion that the scheduled sleeps never exceed the intended maximum delay (especially given the new jitter behavior).

Copilot uses AI. Check for mistakes.
@github-actions github-actions bot mentioned this pull request Apr 13, 2026
@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 83/100

Excellent test quality

Metric Value
New/modified tests analyzed 4
✅ Design tests (behavioral contracts) 4 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 3 (75%)
Duplicate test clusters 0
Test inflation detected ⚠️ YES (both test files exceed 2:1 ratio)
🚨 Coding-guideline violations None

Test Classification Details

All 4 tests
Test File Classification Issues Detected
should retry issue creation on transient rate limit error and succeed create_issue.test.cjs:~680 ✅ Design Mixed: includes call-count assertion (toHaveBeenCalledTimes(2)) alongside behavioral assertions
should fail after exhausting retries on persistent rate limit error create_issue.test.cjs:~706 ✅ Design expect(result.error).toBeDefined() is weak — doesn't verify error message content; call-count assertion is implementation detail
should add random jitter to delay when jitterMs is configured error_recovery.test.cjs:~152 ✅ Design Asserts on log message format ("after 700ms delay") — brittle if log wording changes; no error path
should not add jitter when jitterMs is 0 error_recovery.test.cjs:~180 ✅ Design Asserts on log message format — same brittleness as above; good edge-case coverage (zero value)

Minor Observations (not blocking)

⚠️ should fail after exhausting retries on persistent rate limit error (create_issue.test.cjs)

Observation: expect(result.error).toBeDefined() only checks existence — it would pass even if the error message is empty or meaningless.
Suggested improvement: Replace with expect(result.error).toContain("Secondary rate limit hit") or similar to verify the error message propagates correctly.

⚠️ should add random jitter... / should not add jitter when jitterMs is 0 (error_recovery.test.cjs)

Observation: Both tests assert on a core.info log message string ("after 700ms delay", "after 200ms delay"). If the log wording is changed, the tests break — not because the behavior is wrong, but because the log format changed.
Alternative: Consider exposing the delayWithJitter calculation as a separate utility function and testing it directly, or asserting on the sleep() call duration rather than the log message.


Test Inflation Flag

File Test additions Production additions Ratio
create_issue.test.cjs +55 +26 2.1:1 ⚠️
error_recovery.test.cjs +42 +6 7.0:1 ⚠️

Both files exceed the 2:1 threshold. This accounts for a 10-point deduction. However, context matters here: the production changes are intentionally minimal (adding jitterMs to a config and wrapping two calls in withRetry), while the tests cover multiple scenarios of the new behavior — the inflation is justified by the feature's nature.


Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 0 tests — no Go test files changed
  • 🟨 JavaScript (*.test.cjs): 4 tests (vitest)

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All four new tests verify observable behavioral contracts of the retry-with-jitter feature. The inflation flag is raised as an observation but is contextually justified.


📖 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.

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

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: 83/100. Test quality is excellent — 0% of new tests are implementation tests (threshold: 30%). All four new tests verify observable behavioral contracts of the retry-with-jitter feature. See the full report in the comment above.

@pelikhan
Copy link
Copy Markdown
Collaborator

Copilot AI and others added 2 commits April 13, 2026 16:53
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 13, 2026

@copilot review all comments, fix https://github.com/github/gh-aw/actions/runs/24354035161/job/71116005206

Addressed all review comments in 99a7bfd and 4df60c1:

  1. JSDoc fix — Aligned jitterMs default documentation from 0 to 100 to match DEFAULT_RETRY_CONFIG
  2. CI fix — Updated argument_syntax_test.go expectation from remove [pattern] to remove [filter] (pre-existing mismatch from fix: resolve 11 CLI help text consistency issues #26047)
  3. Delay bounds test — Added assertion that retry delays never exceed maxDelayMs + jitterMs (55s bound)

The non-idempotency suggestion from the automated reviewer (adding searchForExistingParent guard inside the retry loop) was not applied — findOrCreateParentIssue already searches before creating, and the retry window (≤45s) is short enough that duplicate parent issues from concurrent retries are extremely unlikely.

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 /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GO111MODULE .cfg git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile /usr/bin/git 7993986/b196/_pkgit TJ4J/EoB_P8I8Hxwrev-parse 64/pkg/tool/linu--show-toplevel git (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 /tmp/go-build311-p -trimpath 64/bin/go -p github.com/githu-o -lang=go1.25 go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE /usr/lib/systemd-test.v=true (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 --show-toplevel x_amd64/vet /opt/hostedtoolcache/node/24.14.1/x64/bin/node -json GO111MODULE 64/pkg/tool/linu--show-toplevel /opt/hostedtoolcache/node/24.14.1/x64/bin/node /tmp�� Value: ${{ github.actor }} 64/pkg/tool/linuremote.origin.url /usr/bin/infocmp g_.a GO111MODULE 64/pkg/tool/linu--show-toplevel infocmp (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 se 8127051/b111/vet.cfg /usr/bin/git -json rk 64/bin/go git -C /tmp/gh-aw-test-runs/20260413-164153-32207/test-759622872/.github/workflows rev-parse om/myorg/repo.git -json GO111MODULE 64/bin/go git (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 8/001/test-complex-frontmatter-with-tools.md CLJOlIPxV ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/xrepos/{owner}/{repo}/actions/runs/12345/artifacts env ortcfg GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha -test.paniconexit0 -test.v=true /usr/bin/git -test.timeout=10git -test.run=^Test -test.short=true--show-toplevel git rev-�� --show-toplevel go /usr/bin/git 2179391470/001 Kt0zQSK0W ck git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel /opt/hostedtoolcache/go/1.25.8/x1 /usr/bin/git Imports395677780git pkg/mod/golang.orev-parse (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 --show-toplevel x_amd64/compile /usr/bin/git -json qrk06zUvD ache/go/1.25.8/x64/pkg/tool/linu--show-toplevel git rev-�� --show-toplevel ache/go/1.25.8/x^remote\..*\.gh-resolved$ /usr/bin/git ortcfg GO111MODULE ache/go/1.25.8/x--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 -goversion go1.25.8 -c=4 -nolocalimports -importcfg /tmp/go-build3427993986/b224/importcfg -pack 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 -json sonrpc2/conn.go 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v9 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE wasm.s sm.s�� e_wasm.s GO111MODULE x_amd64/asm GOINSECURE GOMOD GOMODCACHE x_amd64/asm (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 /tmp/gh-aw-test-runs/20260413-164153-32207/test-2982178615 rev-parse /usr/bin/git @{u} /common.go x_amd64/compile git conf�� user.email test@example.com /usr/bin/git m/workflows GO111MODULE 64/pkg/tool/linu--show-toplevel 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 --show-toplevel 029NoPl/KBPqmzUXp6OGyvU4qtQm /usr/bin/git ub/workflows g/catalog.go x_amd64/compile git init�� bytealg/indexbyt/tmp/TestHashConsistency_GoAndJavaScript944910528/001/test-frontmatter-with-arragit x_amd64/compile /usr/bin/git -json GO111MODULE 64/pkg/tool/linu--show-toplevel git (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 ithub/workflows/artifacts-summary.md -trimpath ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -p github.com/githurev-parse -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/link unpa�� 8127051/b444/timeutil.test -q 8127051/b444/importcfg.link -c=4 -nolocalimports -importcfg W0VPsKVyXPZlC/uItd0r7K0_37SYBDlan2/iZ31c6N3UWAhfWKKjjpb/pnOHWmOWremote2 (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v7
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha 4153-32207/test-3852909506/.github/workflows om/modelcontextprotocol/go-sdk@v1.5.0/internal/jsonrpc2/conn.go ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile env 7993986/b231/_pkg_.a gNV_/-ERQMY_tDmUJytyNgNV_ 7993986/b231=&gt; GOINSECURE contextprotocol/rev-parse GOMODCACHE FLVpVkE/ejkVgLX7-44yBUCsWhg_ (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha RequiresMinIntegrity2012520069/001 vMoO/r1c5PlYHcFDLvhFNvMoO ache/go/1.25.8/x64/pkg/tool/linux_amd64/vet GOINSECURE ntio/asm/keyset GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linuTest User env D3ub/0rq7wfyhTvls2xI9D3ub GO111MODULE e/git-upload-pack GOINSECURE GOMOD GOMODCACHE /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/asm (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v7 --jq .object.sha 4153-32207/test-1316447584 V4ci/NWzImF-917Hk3aRqV4ci ache/go/1.25.8/x64/pkg/tool/linux_amd64/link GOINSECURE g/x/crypto/chachrev-parse GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -V=f�� 8127051/b412/fileutil.test Bcts/l-3Xgegn_V4R30X4Bcts 8127051/b412/importcfg.link GOSUMDB GOWORK 64/bin/go LF3UeM0V_54WW/fiucaT9ZeFc2kAZlPnrepos/{owner}/{repo}/actions/runs/2/artifacts (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 /home/REDACTED/work/gh-aw/gh-aw/.github/workflows/agentic-observability-kit.md x_amd64/compile /usr/bin/git b/workflows GO111MODULE x_amd64/compile git conf�� user.name Test User /usr/bin/git b/workflows GO111MODULE x_amd64/compile 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 sistency_GoAndJavaScript944910528/001/test-empty-frontmatter.md stmain.go ache/go/1.25.8/x64/pkg/tool/linux_amd64/link -p main -lang=go1.25 ache/go/1.25.8/x64/pkg/tool/linux_amd64/link /tmp�� 8127051/b449/typeutil.test -dwarf=false 8127051/b449/importcfg.link go1.25.8 -c=4 -nolocalimports rFoiYicFsYe-O/_kz8wMEZNDzYl9ptOGPo/5GniUk8RBwwF8S8eKncR/bXjFK1lrFoiYicFsYe-O (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 /tmp/go-build3298127051/b406/constants.test -importcfg 1/x64/bin/node -s -w -buildmode=exe 1/x64/bin/node t-23�� bility_SameInputSameOutput2028511172/001/stability-test.md my-default /usr/bin/git /tmp/go-build311git -trimpath 64/bin/go git (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 64/pkg/tool/linux_amd64/compile GOINSECURE bug GOMODCACHE 64/pkg/tool/linux_amd64/compile env 1316447584 k3aRqV4ci 64/pkg/tool/linux_amd64/link GOINSECURE a20poly1305 GOMODCACHE 64/pkg/tool/linux_amd64/link (http block)
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 0/internal/language/common.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a GO111MODULE ger.test GOINSECURE gset GOMODCACHE ger.test (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 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env ithub/workflows Cy4PJHJpH 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a Zf4ikgLhb /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/12346/artifacts
    • Triggering command: /usr/bin/gh gh api --paginate repos/{owner}/{repo}/actions/runs/12346/artifacts --jq .artifacts[].name GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env til.go o 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD abis 9l/YpuvsMqdrKBw8d7ETVUt/bzEaXbHlremote.origin.url (http block)
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env or.md 6D-KwQuTc ache/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 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env 1316447584 06SIChxms 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 SUy_HbpQE 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linutest@example.com env 3431303608 InX8DV7o_ 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (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 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linutest@example.com env 1316447584 GO111MODULE 64/pkg/tool/linux_amd64/compile GOINSECURE rm abis 64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 0/internal/stringset/set.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD abis 64/pkg/tool/linux_amd64/compile env g_.a sNGC5r73k ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu-trimpath (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 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a go /opt/hostedtoolcache/go/1.25.8/x64/bin/go GOINSECURE /bidi GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 rotocol/go-sdk@v1.5.0/jsonrpc/jsonrpc.go 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linuTest User env 3431303608/.github/workflows LamLkoYmy 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile (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 64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/compile env g_.a GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD abis ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 0/internal/tag/t-nolocalimports 64/pkg/tool/linu-importcfg GOINSECURE GOMOD abis 64/pkg/tool/linu/home/REDACTED/work/gh-aw/gh-aw/scripts/lint_error_messages_test.go env til.go til_test.go 64/pkg/tool/linux_amd64/vet GOINSECURE age GOMODCACHE 64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path -c=4 -nolocalimports -importcfg /tmp/go-build3298127051/b411/importcfg -pack /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/fileutil.go /home/REDACTED/work/gh-aw/gh-aw/pkg/fileutil/tar.go env -json GO111MODULE 64/bin/go 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 100 GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (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 64/pkg/tool/linuremote.origin.url env tants.go ne_constants.go x_amd64/compile GOINSECURE s.o 64/src/runtime/igithub.event.issue.number x_amd64/compile (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 --show-toplevel 64/pkg/tool/linux_amd64/compile /usr/bin/git g_.a sNGC5r73k ache/go/1.25.8/x--show-toplevel git rev-�� --show-toplevel ache/go/1.25.8/x64/pkg/tool/linu-trimpath /usr/bin/git ortcfg kTMme1tRE ache/go/1.25.8/xgit-upload-pack &#39;origin&#39; 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 edOutput181402383/001 YGaDW_VvF 64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD GOMODCACHE 64/pkg/tool/linux_amd64/vet env ortcfg Ffi6x77fi ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linuremote.origin.url (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 -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (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 -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE x_amd64/asm GOINSECURE GOMOD GOMODCACHE x_amd64/asm env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (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 -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile (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 g_.a lNGu_38wk ntdrain.test GOINSECURE jsonschema GOMODCACHE ntdrain.test 2981�� Elygkb-do GO111MODULE ache/go/1.25.8/x64/pkg/tool/linux_amd64/compile GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linuconfig (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 64/pkg/tool/linux_amd64/compile env g_.a YfB4YDUdE ache/go/1.25.8/x64/pkg/tool/linux_amd64/asm GOINSECURE GOMOD GOMODCACHE ache/go/1.25.8/x64/pkg/tool/linu--jq (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 OUTPUT -d 168.63.129.16 go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE wasm.s (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go OUTPUT -d 168.63.129.16 go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build3298127051/b397/cli.test /tmp/go-build3298127051/b397/cli.test -test.testlogfile=/tmp/go-build3298127051/b397/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true -nolocalimports -importcfg /tmp/go-build3427993986/b196/importcfg -pack -o /tmp/go-build311-I -trimpath 64/bin/go -p main -lang=go1.25 go (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 /tmp/go-build311-I -trimpath 64/bin/go -p main -lang=go1.25 go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)

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

@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

Hey @Copilot 👋 — great work tackling the create_issue rate-limit flakiness! Adding jitter to withRetry is exactly the right approach for desynchronizing concurrent callers, and the test coverage across both error_recovery.test.cjs and create_issue.test.cjs is thorough.

One thing flags this PR for focus: there's an unrelated change bundled in alongside the retry/jitter work:

  • Unrelated Go test tweakcmd/gh-aw/argument_syntax_test.go updates the remove command's expected Use string from "remove [pattern]" to "remove [filter]". This touches a completely separate area of the codebase (the Go CLI layer vs. the JavaScript safe-output handler) and belongs in its own PR with context about why the rename is needed.

If you'd like a hand splitting this out, you can assign this prompt to your coding agent:

In the PR branch `copilot/deep-report-add-concurrency-throttling`, revert the change to
`cmd/gh-aw/argument_syntax_test.go` (the single-line update from `"remove [pattern]"` to
`"remove [filter]"`). That change is unrelated to the retry-with-jitter work and should be
proposed in a separate PR.

Generated by Contribution Check · ● 2.6M ·

@pelikhan pelikhan merged commit b4a4e7c into main Apr 13, 2026
54 of 55 checks passed
@pelikhan pelikhan deleted the copilot/deep-report-add-concurrency-throttling branch April 13, 2026 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[deep-report] Add concurrency throttling to safe-output create_issue to prevent rate-limit burst

3 participants