From 8b75299378455b4090715ee096b1a8ecdd2b2b45 Mon Sep 17 00:00:00 2001 From: pc-gemini Date: Thu, 13 Aug 2026 02:35:11 +0900 Subject: [PATCH] fix(ci): retry only the answers that can change on a second attempt Treating every 4xx as final would have failed a release on a 429 rate limit or a 408 timeout, which are both worth another attempt. Retry those two along with 5xx and transport failures, and report anything else immediately. The retry bookkeeping now lives after the case statement rather than inside a branch, so a retryable status cannot leave the loop spinning without a delay or an attempt count. --- .github/workflows/release-xmemo-skill.yml | 32 ++++++++++++++--------- test/release-workflow.test.js | 7 ++++- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release-xmemo-skill.yml b/.github/workflows/release-xmemo-skill.yml index 57fc827..bdc371d 100644 --- a/.github/workflows/release-xmemo-skill.yml +++ b/.github/workflows/release-xmemo-skill.yml @@ -205,24 +205,30 @@ jobs: echo "Announcement accepted: HTTP $http_code" break ;; - 4*) - echo "Announcement rejected with HTTP $http_code; not retrying." >&2 + 000 | 408 | 429 | 5*) + # A transport failure, a timeout, a rate limit, or a server + # error can each succeed later, so these share the retry + # handling below. + : ;; + *) + # Any other answer will not become a 2xx on retry, so it is + # reported at once instead of retried until the step times out. + echo "Announcement rejected with HTTP ${http_code:-none}; not retrying." >&2 head -c 500 "$response_body" >&2 || true echo >&2 exit 1 ;; - *) - if [[ "$attempt" -ge "$max_attempts" ]]; then - echo "Announcement failed after $attempt attempts (last status: ${http_code:-none})." >&2 - head -c 500 "$response_body" >&2 || true - echo >&2 - exit 1 - fi - echo "Announcement attempt $attempt failed (status: ${http_code:-none}); retrying." >&2 - sleep "$((attempt * 3))" - attempt=$((attempt + 1)) - ;; esac + + if [[ "$attempt" -ge "$max_attempts" ]]; then + echo "Announcement failed after $attempt attempts (last status: ${http_code:-none})." >&2 + head -c 500 "$response_body" >&2 || true + echo >&2 + exit 1 + fi + echo "Announcement attempt $attempt failed (status: ${http_code:-none}); retrying." >&2 + sleep "$((attempt * 3))" + attempt=$((attempt + 1)) done - name: Verify xmemo.dev serves this release diff --git a/test/release-workflow.test.js b/test/release-workflow.test.js index 086b370..1e24848 100644 --- a/test/release-workflow.test.js +++ b/test/release-workflow.test.js @@ -25,7 +25,12 @@ test('the Skill release announcement fails fast instead of retrying a rejection' const workflow = await readFile(workflowPath, 'utf8'); assert.doesNotMatch(workflow, /--retry-all-errors/); - assert.match(workflow, /Announcement rejected with HTTP \$http_code; not retrying\./); + assert.match(workflow, /Announcement rejected with HTTP \$\{http_code:-none\}; not retrying\./); + + // Retrying every error turned one rejection into four identical rejections + // followed by an opaque failure. Only answers that can plausibly change on a + // second attempt are retried. + assert.match(workflow, /000 \| 408 \| 429 \| 5\*\)/); }); test('the Skill release is verified against the public endpoint before it is called done', async () => {