From 51a7a0f8915feb4a28836e9ab9ef00ede1379078 Mon Sep 17 00:00:00 2001 From: kjgbot Date: Thu, 10 Sep 2026 07:18:14 +0200 Subject: [PATCH 1/2] fix(review-swarm): give the lens retry budget a delay that can span a 60s backoff Setting no errorHandling does not mean "no retries". The runner's applyReliabilityDefaults() injects strategy:retry / maxRetries:2 / retryDelayMs:1000 whenever errorHandling is absent, so every lens has always had three attempts one second apart. That budget cannot survive a server asking for a longer wait. flows#256: [lens-maintainability] mcp-args --register failed: registration for 'maintainability' was rate-limited; retry after 60s: Workspace write capacity is busy (code: workspace_busy; attempts: 1) Three attempts across two seconds against an advertised 60s. The retries are gone before the requested backoff begins, and the step reports "failed after 2 retries" as though it had waited. Sets only retryDelayMs. maxRetries stays at the injected default of 2, so this changes how long the swarm waits, never how many times it tries. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR --- workflows/review-swarm.yaml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/workflows/review-swarm.yaml b/workflows/review-swarm.yaml index e4d106674..1f389f17d 100644 --- a/workflows/review-swarm.yaml +++ b/workflows/review-swarm.yaml @@ -18,6 +18,32 @@ swarm: timeoutMs: 3600000 maxConcurrency: 3 +# Setting NOTHING here does not mean "no retries". The runner's +# applyReliabilityDefaults() injects strategy:retry / maxRetries:2 / +# retryDelayMs:1000 whenever errorHandling is absent, so every lens has always +# had three attempts one second apart. That budget cannot survive a server that +# asks for a longer wait: +# +# [lens-maintainability] mcp-args --register failed: registration for +# 'maintainability' was rate-limited; retry after 60s: Workspace write +# capacity is busy (code: workspace_busy) +# +# Three attempts across two seconds, against an advertised 60s. The retries are +# spent before the backoff the server asked for has even begun, and the lens +# reports "failed after 2 retries" as if it had been patient. +# +# Only retryDelayMs is set. maxRetries stays at the injected default of 2, so +# this changes how long the swarm waits, never how many times it tries, and it +# adds at most 2 x 60s per lens against a 30m lens timeout and a 60m swarm +# timeout -- the ordering invariant above is untouched. +# +# strategy MUST be 'retry' here. applyReliabilityDefaults returns early on +# 'fail-fast' and 'continue', which would strip the injected defaults and drop +# every lens to zero retries -- the opposite of the intent. +errorHandling: + strategy: retry + retryDelayMs: 60000 + agents: # Transcript contract: .github/workflows/scripts/swarm-verdict.sh, # swarm_transcript_verdict(): last non-empty line, surrounding whitespace From 39dd21345abadfa21d55f57fdc8a6fe85e06b824 Mon Sep 17 00:00:00 2001 From: kjgbot Date: Thu, 10 Sep 2026 12:25:03 +0200 Subject: [PATCH 2/2] docs(review-swarm): stop the comment asserting a retry count it does not set The maintainability lens reviewing this PR flagged that "maxRetries stays at the injected default of 2" is a claim about code in another repository. If the runner default changes, or someone adds maxRetries to this block, the comment becomes quietly wrong while the YAML stays correct. Reworded to state the shape rather than the figure: maxRetries is deliberately not set, the count lives in the runner, and what this change guarantees is that it alters how long the swarm waits, never how many attempts it makes. The current default is still mentioned, but as an illustration of the worst-case cost rather than as a guarantee. No behaviour change: errorHandling is still {strategy: retry, retryDelayMs: 60000} and swarm.timeoutMs is unchanged, both asserted after editing. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR --- workflows/review-swarm.yaml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/workflows/review-swarm.yaml b/workflows/review-swarm.yaml index 1f389f17d..2df0e85db 100644 --- a/workflows/review-swarm.yaml +++ b/workflows/review-swarm.yaml @@ -32,10 +32,17 @@ swarm: # spent before the backoff the server asked for has even begun, and the lens # reports "failed after 2 retries" as if it had been patient. # -# Only retryDelayMs is set. maxRetries stays at the injected default of 2, so -# this changes how long the swarm waits, never how many times it tries, and it -# adds at most 2 x 60s per lens against a 30m lens timeout and a 60m swarm -# timeout -- the ordering invariant above is untouched. +# Only retryDelayMs is set here. maxRetries is deliberately NOT set, so it +# keeps whatever applyReliabilityDefaults injects (2 at the time of writing). +# Stating it that way on purpose: the count lives in the runner, not in this +# file, so a comment claiming a specific number would silently become wrong +# either when the runner default changes or when someone adds maxRetries to +# this block. What this change guarantees is the shape, not the figure -- it +# alters how long the swarm waits between attempts, never how many it makes. +# +# Worst case cost, using the current default: 2 delays x 60s = 120s added per +# lens, against a 30m lens timeout and a 60m swarm timeout. The +# 60m < 65m < 75m ordering invariant above is untouched. # # strategy MUST be 'retry' here. applyReliabilityDefaults returns early on # 'fail-fast' and 'continue', which would strip the injected defaults and drop