@@ -7,11 +7,10 @@ description: Drive a PR to a clean review (Greptile 5/5, zero open threads) —
77
88Owns a PR end-to-end through review: ship it, wait for the automatic review round, and if it
99isn't already clean, drive fix → reply → resolve → re-review cycles until Greptile reports 5/5
10- and there are zero open comment threads. Also keeps the branch mergeable against staging — a
11- long-running loop spans hours during which staging can drift out from under the PR and produce
12- a real merge conflict, not just the stray-local-commit drift ` /ship ` 's sync check catches.
13- Designed to be run under ` /loop ` (no fixed interval — let it self-pace on review latency) so it
14- survives across multiple wakeups in the same session.
10+ and there are zero open comment threads. Also keeps the branch mergeable against staging, since
11+ a long babysit session can outlast staging moving underneath it. Designed to be run under
12+ ` /loop ` (no fixed interval — let it self-pace on review latency) so it survives across multiple
13+ wakeups in the same session.
1514
1615## When to use
1716
@@ -36,10 +35,9 @@ round. Always check both conditions freshly after every push.
3635
3736## Loop
3837
39- 1 . ** Check current state** before doing anything — this includes mergeable state, not just
40- review state:
38+ 1 . ** Check current state** before doing anything, including whether the PR is still mergeable:
4139 ``` bash
42- gh pr view < n> --json mergeable,mergeStateStatus
40+ gh pr view < n> --json mergeable
4341 gh pr view < n> --json comments -q ' [.comments[] | select(.author.login=="greptile-apps")] | last | .body'
4442 gh api graphql -f query='
4543 query { repository(owner: "<owner>", name: "<repo>") { pullRequest(number: <n>) {
@@ -54,44 +52,16 @@ round. Always check both conditions freshly after every push.
5452 stop yet: re-run the same query with ` after: "<endCursor>" ` and keep paging until
5553 ` hasNextPage ` is ` false ` before evaluating "clean." A PR with more than 50 threads is rare but
5654 stopping on a partial page would silently miss unresolved ones past the cutoff.
57- ` mergeable ` is ` UNKNOWN ` for a few seconds right after any push or base-branch move while
58- GitHub computes it — re-poll ` gh pr view <n> --json mergeable ` every few seconds until it
59- settles to ` MERGEABLE ` or ` CONFLICTING ` before acting on it; don't treat ` UNKNOWN ` as either.
60- If ` mergeable ` is ` CONFLICTING ` , skip straight to step 2 (Resolve merge conflicts) — do not
61- evaluate review cleanliness yet, since Greptile/Cursor threads anchored to a conflicting diff
62- can be stale and CI can't even run to confirm anything.
63- If ` mergeable ` is ` MERGEABLE ` , Greptile is 5/5, and every thread across all pages has
64- ` isResolved: true ` , stop — report the outcome (see "Reporting" below) and skip the rest of
65- this list.
66-
67- 2 . ** If ` mergeable ` is ` CONFLICTING ` ** , resolve it before anything else this round. This can
68- happen even on a PR that was clean at creation, since staging moves several times a day —
69- recheck every iteration, don't assume it's a one-time state handled by ` /ship ` .
70- ``` bash
71- git status # stash -u first (ship-sync-fix pattern) if anything uncommitted
72- git fetch origin staging
73- git rebase origin/staging
74- ```
75- Resolve each conflicted file on its actual merits — open it, read both sides inside the
76- ` <<<<<<< ` / ` ======= ` / ` >>>>>>> ` markers, and keep the intent of * both* changes where they're
77- not truly contradictory. Never resolve with a blanket ` git checkout --ours ` /` --theirs ` across
78- a whole file — that silently discards one side's real change instead of merging it. ` git add `
79- each resolved file, then ` git rebase --continue ` ; repeat until the rebase finishes clean (a
80- rebase with ** zero remaining conflicts** does not by itself mean the resolution is correct —
81- see the next point).
82- - A conflict resolution is a code change like any other: before pushing, run this repo's
83- typecheck/lint pass on the touched files (the same checks ` /ship ` step 6 runs) — merge
84- markers can resolve syntactically clean and still be semantically wrong or fail to compile.
85- - Push with ` git push --force-with-lease ` — a rebase here always rewrites already-published
86- history, so a plain ` git push ` will be rejected.
87- - Re-poll ` gh pr view <n> --json mergeable,mergeStateStatus ` until it reports ` MERGEABLE `
88- (not ` UNKNOWN ` ) before moving on. If it still reports ` CONFLICTING ` , the rebase resolved
89- against a stale local ` origin/staging ` — ` git fetch origin staging ` again and redo the
90- rebase; don't push a second time believing it's fixed without this recheck.
91- - This push needs a fresh review like any other code change — go to step 8 (re-trigger
92- review) rather than trying to also address old review threads in the same pass, especially
93- if the conflict touched files a thread was anchored to (that anchor may no longer be valid
94- against the resolved code). Re-evaluate thread state fresh once the new round lands.
55+ If ` mergeable ` comes back ` CONFLICTING ` , go fix that first (step 2) before evaluating review
56+ state — a conflicting PR can't run CI, and this can happen mid-loop even on a PR that was
57+ clean at creation, since staging moves several times a day. Otherwise, if Greptile is 5/5 and
58+ every thread across all pages has ` isResolved: true ` , stop — report the outcome (see
59+ "Reporting" below) and skip the rest of this list.
60+
61+ 2 . ** If the PR has a merge conflict** , fix it: ` git fetch origin staging ` , `git rebase
62+ origin/staging`, resolve the conflicts for real (don't just take one side blindly), then push
63+ with ` --force-with-lease ` . Continue on to step 8 to trigger a fresh review of the resolved
64+ code.
9565
96663 . ** If no review has run yet** (fresh PR, no Greptile/Cursor comments): they usually run
9767 automatically on PR open — confirm via ` gh pr checks <n> ` (look for ` Cursor Bugbot ` /
@@ -130,11 +100,7 @@ round. Always check both conditions freshly after every push.
130100 committing — not just lint/typecheck/boundary-validation, but also the conditional ` /cleanup `
131101 (if this round's fix touched UI code) and ` /db-migrate ` (if it touched schema/migrations)
132102 gates from ` /ship ` steps 4 and 5. A review-fix round is still a code change and can trip
133- either gate just as easily as the original commit did. This is the same sync check as step 2
134- above but for local-drift, not for the base-branch textual conflicts step 2 handles — step 2
135- already left the branch rebased onto current ` origin/staging ` when it ran, so this step is
136- normally a no-op in that case, but still run it: it also catches stray local commits that
137- have nothing to do with merge conflicts.
103+ either gate just as easily as the original commit did.
138104
1391057 . ** Commit and push** the round's fixes as one commit — ` --force-with-lease ` whenever step 6's
140106 sync check rewrote history, which includes a plain ` git rebase origin/staging ` that completed
@@ -164,17 +130,15 @@ round. Always check both conditions freshly after every push.
164130 in a sleep loop. Pass the same ` /loop babysit PR <n> ` prompt on each wakeup so the loop
165131 resumes correctly.
166132
167- 10 . ** Stop conditions** : clean state reached (see above), or the same unresolved finding
168- survives two consecutive rounds with no new information, or the same merge conflict recurs
169- every round with no new information (e.g. a semantic conflict you can't confidently resolve
170- without changing intent), or the user interrupts — surface any of these to the user instead
171- of looping forever.
133+ 10 . ** Stop conditions** : clean state reached (see above), or the same unresolved finding or
134+ merge conflict survives two consecutive rounds with no new information (surface it to the
135+ user instead of looping forever), or the user interrupts.
172136
173137## Reporting
174138
175- When the loop ends, summarize: how many rounds it took, what was actually fixed (one line each) ,
176- what was pushed back on as a false positive and why, how many merge conflicts came up and against
177- which staging commits (if any), and the final Greptile score / thread count / mergeable state .
139+ When the loop ends, summarize: how many rounds it took, what was actually fixed (one line each,
140+ including any merge conflict resolved), what was pushed back on as a false positive and why, and
141+ the final Greptile score / thread count.
178142
179143## Hard rules
180144
@@ -184,9 +148,4 @@ which staging commits (if any), and the final Greptile score / thread count / me
184148 pattern elsewhere in the codebase solving the same class of problem and match it.
185149- Never silently drop a finding — every thread gets either a code fix or a reasoned reply.
186150- Always re-run the ` /ship ` -style sync check before every push in the loop, not just the first.
187- - Never resolve a merge conflict with a blanket ` --ours ` /` --theirs ` across a whole file — read
188- both sides and preserve the real intent of each; a wrong resolution ships silently since
189- nothing else catches it.
190- - Never treat ` mergeable: UNKNOWN ` as either ` MERGEABLE ` or ` CONFLICTING ` — poll until it settles.
191- - Never evaluate review-thread cleanliness while ` mergeable ` is ` CONFLICTING ` — resolve the
192- conflict first, since threads anchored to a conflicting diff can be stale.
151+ - Never resolve a merge conflict by blindly taking one side — check the actual diff.
0 commit comments