Repository navigation
feat(triage-daemon): label bot PRs and assign them to whoever added BOT_PR - #5759
Conversation
…OT_PR A PR opened by the BOT_PR flow is always authored by the bot's credential, so nothing on the PR said it was a bot PR or who asked for it - that lived only in the issue's label history. When the flow has just opened the PR, mark_pr_opened() now also adds BOT_PR_OPENED to the PR and assigns it to the login that last added BOT_PR to the issue. Best effort: the PR is already open, so a failed lookup or edit is logged, not raised, and the assignee is a separate edit so a bad login can't drop the label. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n that succeeds Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Review follow-ups. Marking a PR as the bot's no longer rides on cleanup: mark_pr_opened() and flag_pr_for_review() take opened_by_bot, which process_bot_pr_issue() passes for a PR it just opened. BOT_PR_OPENED now goes in the same edit as the review labels instead of a third gh call. The requester lookup and assignee edit have a timeout and are guarded against gh erroring or hanging, and labeled events with a null actor are filtered out so 'null' is never taken for a login. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
springfall2008
left a comment
There was a problem hiding this comment.
Automated comment from the triage bot.
Review at commit 61c6c33: 1 low finding, posted inline; no correctness bugs found, nothing body-level.
What I checked beyond the diff. The requester lookup's exact gh call shape runs cleanly against the live API, and on a real BOT_PR issue (#5732) it returns the right login (chalfontchubby); issue events are returned oldest-first, so the 'last line is the latest request' assumption holds; the .actor != null filter correctly skips ghost actors. subprocess.TimeoutExpired subclasses SubprocessError, so the single except in assign_bot_pr_requester() covers both a hung lookup and a hung assignee edit. opened_by_bot=True is passed only at the one 'this run just opened it' call site (triage_daemon.py:1558); the PR-found-already-open path stays unclaimed, matching the PR body's stated trade-off. --add-assignee is additive, so the --assignee springfall2008 that /issue-pr's template always sets survives as assignee; and a BOT_PR labeled event authored by the bot's own credential does occur in this repo's history (#5569) - in that case the assign step targets the already-assigned PR author, a harmless no-op. Nothing in the daemon or the skills queries BOT_PR_OPENED on pull requests (the design docs mention only the issue-side label), so the new PR label cannot trigger any other flow. All new tests pin the new behaviour (they fail if the feature is reverted) and the pre-commit triage-daemon-tests hook runs them.
A lookup that errored (auth expiry, rate limit) returned None exactly like an issue nobody had added BOT_PR to, so the reason was lost. It is now printed with gh's stderr. Review point on #5759. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opened by Claude on behalf of @chalfontchubby.
Problem
A PR opened by the
BOT_PRflow is always authored byspringfall2008, because that's the bot's credential, and/issue-prassigns it tospringfall2008as well. So nothing on the PR itself says it's a bot PR, or who pressedBOT_PRfor it. That's recorded only in the issue's label history. You can't list bot PRs by label, and the person who asked for one can't find it under their assigned PRs.Change
When
process_bot_pr_issue()has just opened the PR (the same condition that already queuesBOT_CLEANUP), the daemon now:BOT_PR_OPENED, the label the issue already gets. It goes in the samegh pr editasBOT_REVIEW/BOT_CLEANUP, so it costs no extra call.gh pr list --label BOT_PR_OPENEDthen lists every bot PR.BOT_PRto the issue. The login is read from the issue's events (labeledevents forBOT_PR; the latest wins, null actors are skipped).springfall2008stays assigned too, sogh pr list --assignee @menow shows the requester their bot PRs.The marking has its own
opened_by_botflag rather than reusingcleanup. A PR found already open on entry may be someone's own, so it is neither labelled nor reassigned.The assignee step is best effort, because by then the PR is already open and labelled. A failed lookup, an unassignable login, or
gherroring or hanging (120 s timeout) is logged and the flow carries on.Nothing queries
BOT_PR_OPENEDon PRs today. Every daemon label query is eithergh issue list(issues only) orgh pr list --label BOT_REVIEW|BOT_CLEANUP, so the new label on PRs can't trigger anything.Already backfilled
I've already applied this by hand to the 79 existing bot PRs, found by the fixed opening line of
/issue-pr's PR body ("This is an automated draft PR generated from issue #N"). All 79 now carryBOT_PR_OPENED. The 56 whose issue has aBOT_PRlabel event are assigned to that person. The other 23 have no such event (opened outside the label flow), so they got the label only.Tests
python3 tools/test_triage_daemon.py: 339 pass. The new tests cover:ghopened_by_bot=TrueBefore the change, the new tests fail. Pre-commit is clean.
The daemon needs a restart after merge to pick this up.
🤖 Generated with Claude Code