Found while refreshing the dossier. The audit's own drift table records @buddy plan and @buddy resolve being removed from the help text rather than built. #1414 implemented plan. This is its sibling.
resolve has been in the command parser since the command layer shipped, and docs/features/pr-conversations.md describes it twice — including a feature card making a specific promise:
@buddy resolvecloses the threads Buddy opened — not the ones your teammates did — so a fixed review does not leave a page of stale conversation.
There was no handler. Typing it got I don't know how to resolve yet. Try @buddy help. — and help didn't list it.
There was also nothing that could have backed one. No method anywhere in src/ reads a review thread; inlineReviewComments only covers posting a comment, not the thread it starts.
The capability
reviewThreads, gating listReviewThreads and resolveReviewThread.
| GitHub | GitLab | Bitbucket | |
|---|---|---|---|
reviewThreads | ✅ | ✅ (discussions) | ❌ |
Separate from inlineReviewComments deliberately — a platform can accept a line-anchored comment without modelling the thread, and Bitbucket is exactly that: it resolves threads in its own UI and exposes no API for it.
- GitHub needs GraphQL. REST exposes review comments but neither the threads they belong to nor whether one is resolved.
- GitLab maps onto discussions, filtered to resolvable ones — the same endpoint returns system notes and plain comments that can't be resolved, and including them would hand a caller threads it can do nothing with.
resolveReviewThreadtakes the pull request as well as the thread, for GitLab's sake, where a discussion is addressed under its merge request rather than by a global node id.
The promise is the hard part
Ownership is judged by who started a thread, not who is in it:
const opener = thread.authorLogins[0]So a maintainer replying to a finding doesn't take it away from Buddy, and a teammate's thread Buddy happened to comment on is still not Buddy's to close. Both directions are tested — closing a human's conversation because a bot was asked to tidy up is the failure that actually matters here.
"Nothing of mine is open" and "there is nothing here at all" report differently. They're different answers to the same request, and collapsing them leaves someone wondering whether the command ran.
Tests
2047 → 2060. reviewThreads added to both conformance arrays; the typed NO_CAPABILITIES caught all three providers at compile time, as designed.
Lint ✓ · typecheck ✓ · check:docs ✓ · 2060 pass / 0 fail
🤖 Generated with Claude Code