Skip to content

fix(skills): stop /sweep subagents from stalling or reporting stale status - #2171

Merged
carlos-alm merged 7 commits into
mainfrom
fix/sweep-skill-avoid-premature-completion
Jul 29, 2026
Merged

fix(skills): stop /sweep subagents from stalling or reporting stale status#2171
carlos-alm merged 7 commits into
mainfrom
fix/sweep-skill-avoid-premature-completion

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

  • /sweep subagents 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.
  • One PR's review loop blew past the documented 3-round Greptile retrigger cap (went to 6 rounds) because rounds were tracked mentally rather than checked against live data.
  • A PR was briefly reported "resolved"/ready based 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

  • New "Before you start: how to wait" contract for subagents: poll in a continuous sequence of tool calls, never end the turn to wait passively — applied to CI checks, npm test/npm install, and reviewer response waits.
  • Step 2g now requires counting actual @greptileai comments posted (mechanical check) before every retrigger, and hard-stops at 3 with Status: needs-human-review regardless of whether a real bug was just fixed.
  • New Step 2h.1: a mandatory final live re-check of all comments immediately before writing the Step 2i result, so Status: ready can't be based on stale data.
  • New orchestrator-level guidance: when resuming a stalled subagent, don't substitute your own manual spot-check for the subagent's own final verification.

Test plan

  • Read through the full updated skill file for internal consistency (step cross-references, rule wording)
  • N/A — this is a skill/prompt file, not executable code; no test suite applies

…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.
Comment thread .claude/skills/sweep/SKILL.md Outdated
Comment on lines +259 to +260
--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."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread .claude/skills/sweep/SKILL.md Outdated
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Hard stop bypasses final verification

When the trigger count reaches three, this branch jumps directly to Step 2i instead of running the mandatory Step 2h.1 check, causing newly arrived comments to remain undiscovered and unacknowledged in the final needs-human-review report.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-apps

greptile-apps Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The sweep instructions now prevent passive subagent stalls and require live review-state verification.

  • Requires continuous polling for CI, long-running commands, and reviewer responses.
  • Enforces the three-trigger Greptile cap using actor-scoped, pagination-safe live comment data.
  • Routes cap-hit branches through the final live comment check before reporting.
  • Requires resumed subagents to perform their own final verification.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
.claude/skills/sweep/SKILL.md Adds polling, mechanical trigger-budget enforcement, and mandatory final verification; the previously reported counting and hard-stop defects are fixed.

Reviews (5): Last reviewed commit: "Merge branch 'main' into fix/sweep-skill..." | Re-trigger Greptile

Comment thread .claude/skills/sweep/SKILL.md Outdated
Comment on lines +260 to +262
--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."
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Actor binding breaks trigger count

When the sweep reaches Step 2g, the command passes jq's --arg option directly to gh api, which does not bind it as part of the --jq filter, causing the mandatory actor-scoped trigger count to fail instead of producing the numeric value needed to enforce the cap.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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" '...'.

Comment thread .claude/skills/sweep/SKILL.md Outdated
Comment on lines +260 to +262
| 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."
```

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Paginated count breaks cap enforcement

When the PR's issue comments span multiple API pages, the downstream jq expression emits a separate count for each page, producing a multiline trigger_count that fails the numeric hard-cap comparison and permits additional Greptile retriggers.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

Comment on lines +259 to +260
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')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 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.

Fix in Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@carlos-alm
carlos-alm merged commit ab173e3 into main Jul 29, 2026
15 checks passed
@carlos-alm
carlos-alm deleted the fix/sweep-skill-avoid-premature-completion branch July 29, 2026 19:38
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant