Skip to content

Commit a733998

Browse files
fix(skills): flip PR to ready before waiting on CodeRabbit to avoid a draft deadlock (#4473)
* fix(skills): flip PR to ready before waiting on CodeRabbit to avoid a draft deadlock CodeRabbit never reviews a draft PR. The monitor loop could enter or continue its CodeRabbit/threads wait while the PR was still draft, deadlocking silently (observed 2026-07-16). Adds a hard ordering invariant in §5 (flip ready as soon as draft CI is green, before any wait), plus a belt-and-braces re-check at the top of every monitor loop pass: if still isDraft with CI green, run `gh pr ready` again — covers a loop started pre-flip or a rebase/force-push that reverted the PR to draft. Closes #4450 Claude-Session: https://claude.ai/code/session_01WfNC8bt1TgL4AsiYgCEGup * fix(skills): make the draft-guard CI-green check reject empty rollups and accept neutral/skipped Claude-Session: https://claude.ai/code/session_01WfNC8bt1TgL4AsiYgCEGup * fix(skills): handle gh pr ready failure and re-run the draft guard after CI goes green Claude-Session: https://claude.ai/code/session_01WfNC8bt1TgL4AsiYgCEGup
1 parent 1b087d7 commit a733998

2 files changed

Lines changed: 52 additions & 1 deletion

File tree

.claude/skills/pull-request/SKILL.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,12 +97,14 @@ PR title must follow `type(scope): description` (conventional commits). Link the
9797
- Checkbox sections (Validation, Guardrails): check each box that applies (`- [x]`), leave unchecked only what genuinely does not apply
9898
- Follow any instructions in the template (e.g. "Delete this section if not applicable")
9999

100-
Once **draft CI passes** and the PR is ready for human review, convert to ready:
100+
Once **draft CI passes**, convert to ready **immediately, before anything else**:
101101

102102
```bash
103103
gh pr ready <number>
104104
```
105105

106+
> **Ordering invariant (hard requirement):** CodeRabbit never reviews a draft PR. Flipping to ready is a mandatory prerequisite for entering — or continuing — any wait on CodeRabbit/review threads. Do it the moment draft CI is green, BEFORE starting section 6. Waiting on CodeRabbit while the PR is still draft is a guaranteed silent deadlock (observed 2026-07-16, issue #4450).
107+
>
106108
> Some bots (e.g. CodeRabbit) trigger on ready, not on CI completion. After converting, do a **preliminary review pass** before entering the main loop:
107109
>
108110
> ```bash
@@ -115,6 +117,9 @@ gh pr ready <number>
115117
116118
## 6. Monitor loop (autonomous)
117119
120+
The PR must already be ready (see §5) before this loop starts — CodeRabbit
121+
never reviews a draft, so entering this loop while still draft deadlocks.
122+
118123
After `gh pr ready`, run an autonomous polling loop until either CI is green
119124
with zero unresolved threads for 3 consecutive passes (~9 min) or the safety
120125
limit (10 iterations) trips.
@@ -126,6 +131,9 @@ PR=<number>
126131
```
127132
128133
Per pass:
134+
0. **Draft guard** (belt-and-braces) → if still `isDraft: true` and CI is
135+
green, `gh pr ready "$PR"` immediately — covers a loop that started
136+
pre-flip, or a rebase/force-push that reverted the PR to draft
129137
1. Wait CI → fix + /verify + commit + push if red, else continue
130138
2. Check mergeable — `CONFLICTING` stops, `UNKNOWN` retries
131139
3. Grace `sleep 180` + adaptive recheck of pending review checks

.claude/skills/pull-request/references/monitor-loop.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,24 @@ PR=<number>
1313

1414
After `gh pr ready`, run this loop yourself — do not wait for the user.
1515

16+
**Ordering invariant:** the PR must be ready (not draft) before this loop
17+
starts — CodeRabbit never reviews a draft PR, so waiting on it while draft is
18+
a guaranteed silent deadlock. Step 0 below is a defensive re-check, not a
19+
substitute for flipping to ready in §5 before entering the loop.
20+
1621
## Loop procedure
1722

1823
```text
1924
consecutive_zero = 0
2025
2126
REPEAT:
27+
0. Draft guard (belt-and-braces) → see 6a-0. If still draft with CI green, flip to ready now.
2228
1. Wait for CI → sleep 30 then gh pr checks "$PR" --watch
2329
2. If CI fails → fix, /verify, commit, push, consecutive_zero=0, GOTO 1
30+
2a. Re-run draft guard → see 6a-0. CI is confirmed green here (whether it started
31+
green or just turned green in step 1) — re-checking closes
32+
the gap where a pass starting draft+red would otherwise sail
33+
straight through to mergeability/grace/review-wait still draft.
2434
2b. Check mergeable status → gh pr view "$PR" --json mergeable --jq .mergeable
2535
if "CONFLICTING" → report to user and STOP
2636
if "UNKNOWN" → sleep 30, retry (up to 3 times), then proceed
@@ -34,6 +44,39 @@ REPEAT:
3444
else GOTO 3
3545
```
3646

47+
## 6a-0. Draft guard (belt-and-braces)
48+
49+
Run at the top of **every** pass, before waiting on CI or reading threads.
50+
Covers the race where the loop started before the ready-flip landed, or a
51+
rebase/force-push reverted the PR to draft:
52+
53+
```bash
54+
STATE=$(gh pr view "$PR" --json isDraft,statusCheckRollup)
55+
IS_DRAFT=$(echo "$STATE" | jq -r '.isDraft')
56+
# green = rollup non-empty (an empty rollup right after a force-push/rebase must NOT read as green) AND
57+
# every check is SUCCESS/NEUTRAL/SKIPPED (all non-blocking; a bare FAILURE/CANCELLED or still-pending check stays not-green)
58+
CI_GREEN=$(echo "$STATE" | jq -r '[.statusCheckRollup[]? | (.conclusion // .state)] | length > 0 and all(. as $s | ["SUCCESS","NEUTRAL","SKIPPED"] | index($s) != null)')
59+
60+
if [ "$IS_DRAFT" = "true" ] && [ "$CI_GREEN" = "true" ]; then
61+
if ! gh pr ready "$PR"; then
62+
sleep 5
63+
if ! gh pr ready "$PR"; then
64+
echo "gh pr ready failed twice on PR $PR — stopping to avoid a draft deadlock." >&2
65+
exit 1
66+
fi
67+
fi
68+
fi
69+
```
70+
71+
If `gh pr ready` fails, retry once (5s later); if it still fails, stop and
72+
report to user — never fall through to mergeability/grace/review-wait with
73+
the PR still draft. Continue only once the PR is confirmed non-draft.
74+
75+
If still draft with CI **not** green, do nothing here — fall through to 6a,
76+
fix CI first. Once CI turns green (either at pass start or mid-pass in 6a),
77+
this guard re-runs at step 2a before mergeability/grace/review-wait — never
78+
"next pass."
79+
3780
## 6a. Wait for CI
3881

3982
After any push, wait 30s then watch:

0 commit comments

Comments
 (0)