ci(stack): retry slim pickup when a merge-queued PR holds the branch - #6957
Conversation
There was a problem hiding this comment.
Superseded by a newer AI review
🤖 AI Review
Both independent reviews were available. Claude's single minor finding is confirmed: a persistent push rejection mentioning "merge queue" can cause unlimited redispatches that each succeed. Codex reported no findings.
Findings
| Severity | Location | Category | Sources | Claim |
|---|---|---|---|---|
| 🟡 MINOR | .github/workflows/slim-release-published.yml:167 |
error-handling |
claude | Any push rejection containing "merge queue" enters the hand-off path. If the first queue lookup returns false and no pending run exists, the workflow redispatches the same payload and exits successfully. A persistent rejection mentioning the merge queue can therefore retrigger the workflow indefinitely without reaching the manual-recovery failure. |
Stats
Claude findings: 1 · Codex findings: 0 · Confirmed: 1 · Refuted: 0 · Uncertain: 0
Models: claude-opus-5-5 + gpt-6.1-sol · Trigger: auto · Workflow run
This review runs once per PR. A maintainer can request another with a /ai-review comment.
avallete
left a comment
There was a problem hiding this comment.
Reviewed at fc02fad. The hand-off logic works, and the replay counter bounds the re-dispatch chain flagged on the earlier head. Approve-level, with non-blocking suggestions inline. The main one is concurrency.queue: max.
Dogfood
I extracted the "Apply planned updates" script verbatim and ran it under bash -eo pipefail, with git, gh, bun and pnpm stubbed and sleep fast-forwarded. The GitHub probes are read-only.
| Scenario | Result |
|---|---|
| Push succeeds → PR create/edit path | ✅ |
| Non-merge-queue push rejection → exit 1 with manual steps | ✅ |
Real GH006 text, queue true→false, pending run exists → exit 0, no dispatch, remaining plan items skipped |
✅ |
Same, no pending run, replay unset → dispatch with replay=1, all payload fields set → exit 0 |
✅ |
replay=2 → dispatch replay=3; replay=3, 01, 1; echo x → exit 1, no dispatch |
✅ |
| Queue lookup fails / prints an unexpected value → exit 1 | ✅ |
Queue stays true → exit 1 at the deadline (~1800 s, 61 lookups) |
✅ |
gh run list fails / dispatch fails → exit 1 |
✅ |
Re-dispatched payload (edge-runtime, v1.77.4, 0, v1.77.4-r0) passes validate-payload |
✅ |
Probes against the live repo:
- The 2026-10-01 failure (run 36844058874) rejected the push with
A pull request for this branch has been added to a merge queue. Branches that are queued for merging cannot be updated., so thegrepgate matches the real message. - The
isInMergeQueuequery returns exactlytruefor a branch that is currently queued, andfalseforslim-bump/edge-runtimeand for a nonexistent branch. gh run list --status pendingplus thejqfilter returns0when nothing is pending. Runs created before this PR have the display titleslim-release-publishedwithout a service, so the match only applies to runs dispatched after it merges.actionlintis clean.
Not exercised: the restricted app token (contents + pull-requests write) reading isInMergeQueue. The probes used a user token.
Suggestions
concurrency.queue: max(workflow line 17, outside the diff). This is the race ADR 0026 calls non-atomic: a newer dispatch can become pending between thegh run listlookup and the re-send, and the defaultqueue: singlethen cancels it in favour of the replay. The replay only plans that newer release if it is already listed.queue: maxkeeps up to 100 pending runs in the group and is valid withcancel-in-progress: false(see control workflow concurrency). With it, the eviction cannot happen, the pending-run lookup is only a deduplication step, and the ADR caveat can be removed. One caveat: actionlint 1.7.12 does not know the key yet.- Narrower rejection match. See the inline comment.
- Recovery wording after the queue has cleared. See the inline comment.
- Comment length. See the inline comment.
Minor ADR notes:
- The pending lookup does not see a newer run that is still
requested/queued(a few seconds wide), so the window is slightly wider than "arriving between them". - "waits up to 30 minutes" is really the lesser of 30 minutes and the token-bound cap of about 50 minutes into the step.
|
/ai-review |
There was a problem hiding this comment.
🤖 AI Review
Both independent reviews completed and reported no findings. After reading the full changed workflow, payload validation, diff, and trusted conventions, I found no concrete defects to add.
Findings
No issues found.
Stats
Claude findings: 0 · Codex findings: 0 · Confirmed: 0 · Refuted: 0 · Uncertain: 0
Models: claude-opus-5-5 + gpt-6.1-sol · Trigger: manual · Workflow run
This review runs once per PR. A maintainer can request another with a /ai-review comment.
slim-release-published.ymlforce-pushes one branch per service release line. When that branch's PR sits in the merge queue, GitHub rejects the push (GH006) and the job used to fail, dropping the planned pin until the next upstream release. On 2026-10-01 this lost edge-runtime v1.77.4-r0: the v1.77.3-r0 and v1.77.4-r0 dispatches both hitslim-bump/edge-runtimewhile #6930 was queued (restored by #6955).When a push is rejected because the branch is queued for merging, the Apply step now:
isInMergeQueuefor up to 30 minutes and within the app token's lifetime;client_payload.replaycounter).The concurrency group now keeps every pending run (
queue: max) instead of replacing the pending one, so a replay can never cancel a newer dispatch and its release-visibility wait. A failed queue lookup or dispatch, a queue that holds the branch past the deadline, an exhausted replay budget, and any other push rejection still fail the run with the manual recovery command. ADR 0026 documents the behavior.