fix(skills): stop /sweep subagents from stalling or reporting stale status - #2171
Conversation
…tatus Today's sweep run had two recurring failures: subagents repeatedly ended their turn to passively "wait" for CI/tests/reviews instead of polling (requiring manual SendMessage nudges to resume), and status was reported as "ready" based on a stale check taken before a later Greptile round posted new findings. One PR also blew past the 3-round Greptile retrigger cap because rounds were tracked mentally instead of from live data. Adds an explicit "how to wait" contract (poll in a continuous tool-call sequence, never end the turn to wait), a mechanical trigger-count check before every Greptile retrigger, and a mandatory final live re-check immediately before reporting a result.
| --jq '[.[] | select(.user.login != "greptile-apps[bot]" and (.body | test("^@greptileai\\s*$")))] | length') | ||
| echo "Greptile has been re-triggered $trigger_count time(s) so far." |
There was a problem hiding this comment.
Trigger count includes other users
When a PR already contains exact @greptileai comments from its author, maintainers, or another workflow, this query counts them against the sweep's three-retrigger budget, causing the sweep to stop early and report needs-human-review before using its permitted review rounds.
There was a problem hiding this comment.
Fixed — the trigger-count query now scopes to the authenticated actor (gh api user --jq '.login') instead of user.login != "greptile-apps[bot]", so pre-existing @greptileai comments from the PR author, a maintainer, or another workflow no longer count against this sweep run's own retrigger budget.
| echo "Greptile has been re-triggered $trigger_count time(s) so far." | ||
| ``` | ||
|
|
||
| If `trigger_count` is already **3 or more**: do NOT trigger again, no matter how many real findings you just fixed. Reply to any outstanding comment (per Step 2e) so nothing is left unacknowledged, then skip straight to Step 2i and report `Status: needs-human-review`, noting in Notes how many rounds occurred and what the last item was. Fixing a real bug on round 4+ does not extend the cap — it's a budget on wall-clock and review noise, not a correctness gate; a human reviews the rest. |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed — when the hard cap is already hit, the flow no longer jumps straight to Step 2i. It now runs the mandatory Step 2h.1 final live re-check first (reply to anything new turns up), and only then proceeds to report needs-human-review. Applied the same fix to the equivalent mid-loop cap-hit branch in Step 2h item 4, which had the identical bypass.
Greptile SummaryThe sweep instructions now prevent passive subagent stalls and require live review-state verification.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Reviews (5): Last reviewed commit: "Merge branch 'main' into fix/sweep-skill..." | Re-trigger Greptile |
| --jq --arg me "$me" '[.[] | select(.user.login == $me and (.body | test("^@greptileai\\s*$")))] | length') | ||
| echo "Greptile has been re-triggered $trigger_count time(s) so far by this sweep." | ||
| ``` |
There was a problem hiding this comment.
There was a problem hiding this comment.
Correct catch — this was the syntax bug from my prior commit (gh api --jq does not accept --arg). Already fixed in the very next commit by piping through a separate jq invocation instead: gh api ... --paginate | jq --arg me "$me" '...'.
| | jq --arg me "$me" '[.[] | select(.user.login == $me and (.body | test("^@greptileai\\s*$")))] | length') | ||
| echo "Greptile has been re-triggered $trigger_count time(s) so far by this sweep." | ||
| ``` |
There was a problem hiding this comment.
There was a problem hiding this comment.
Fixed — piped through jq -s (slurp) and iterate .[][] instead of a plain single-array filter, so multiple --paginate pages collapse into one flat count instead of one length per page.
| trigger_count=$(gh api repos/optave/codegraph/issues/<number>/comments --paginate \ | ||
| | jq -s --arg me "$me" '[.[][] | select(.user.login == $me and (.body | test("^@greptileai\\s*$")))] | length') |
There was a problem hiding this comment.
Historical triggers exhaust new sweeps
When the same authenticated GitHub account runs /sweep again for a PR, this query counts its bare @greptileai comments from earlier runs as part of the new sweep's budget, causing the later sweep to stop early with needs-human-review before using its permitted review rounds.
There was a problem hiding this comment.
Disagree, keeping as-is — the cap is deliberately per-PR-lifetime, not per-session. The rule text is explicit: "Hard cap: 3 total Greptile re-triggers per PR" and "it's a budget on wall-clock and review noise, not a correctness gate; a human reviews the rest." If 3 rounds already happened for this PR in an earlier sweep run and the PR still isn't clean, a fresh session should not get a new budget of 3 more triggers — that would let a problematic PR bounce indefinitely between sweep invocations, defeating the noise-budget's purpose. There's also no reliable signal in GitHub comment history to distinguish "this session's" triggers from "an earlier session's" triggers by the same actor, so scoping by session isn't practically implementable from live PR data anyway. Scoping to the authenticated actor (this fix) still correctly excludes other users'/workflows' triggers, which was the actual bug.
There was a problem hiding this comment.
That's a convincing argument on all three counts — the rule text is unambiguous ("per PR"), the noise-budget rationale actively depends on cross-session accumulation, and the session-scoping isn't implementable from comment history anyway. The authenticated-actor scope is the right fix, and counting prior sessions' triggers against the cap is the intended behavior. I withdraw the concern.
Summary
/sweepsubagents repeatedly ended their turn to passively "wait" for CI,npm test, or reviewer responses instead of polling — since a background subagent is never woken up automatically, this stalled the sweep silently until manually resumed via SendMessage.readybased on a stale point-in-time check; two more real Greptile findings arrived shortly after and were fixed, but the report should never have gone out that way.Changes
npm test/npm install, and reviewer response waits.@greptileaicomments posted (mechanical check) before every retrigger, and hard-stops at 3 withStatus: needs-human-reviewregardless of whether a real bug was just fixed.Status: readycan't be based on stale data.Test plan