Summary
tend-mention spins up a full (billable) agent session every time the bot leaves an empty-body APPROVED review on a human-authored PR. The session can never produce an action — it reads the review, recognizes its own approval, and exits silently. This is a third, distinct leg of the no-op-session family you greenlit upstream in #95; it is not covered by either fix filed then (tend#606 = issue_comment leg, now shipped; tend#607 = tend-review self-review leg, still open). The fix lives in the upstream-owned generated tend-mention.yaml ("Do not edit this file directly"), so this asks for your go-ahead to file it at max-sixty/tend — same as #95.
Surfaced by the review-runs sweep (run 27899493170).
Evidence
Three occurrences in a single 24h window, one per human PR the bot approved:
| Run |
PR (author) |
Trigger |
Review |
Outcome |
Cost |
| 27875120333 |
#158 (nedtwigg) |
pull_request_review |
empty-body APPROVED (id 4538038926) |
exited silently |
$0.28 |
| 27879038635 |
#163 (nedtwigg) |
pull_request_review |
empty-body APPROVED (id 4538477275) |
exited silently |
$0.11 |
| 27883636959 |
#164 (nedtwigg) |
pull_request_review |
empty-body APPROVED (id 4538814194) |
exited silently |
$0.10 |
~$0.49 for the window, and it scales linearly with how many human PRs the bot reviews — this was the highest-frequency window recorded this month (see the running tally in #123). It still fires at the current generated workflow version (tend 0.1.6).
Root cause
For a pull_request_review event the verify gate falls through to a "has the bot engaged on this PR?" heuristic:
BOT_REVIEWS=$(gh api --paginate "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" \
--jq '[.[] | select(.user.login == "dormouse-bot")] | length')
if [ "$BOT_REVIEWS" -gt "0" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
When the triggering event is the bot's own review, that review is itself counted as engagement, so BOT_REVIEWS > 0 is always true and the gate returns should_run=true → a no-op session. The issue_comment path has an analogous early-exit (COMMENT_AUTHOR_TYPE == "Bot" → skip); the pull_request_review path has none.
The tend#166 constraint (why not just filter all bot reviews)
tend#166 (closed/implemented) deliberately removed the blanket review.user.login != bot filter so the bot can act on its own suggestion reviews on its own PRs. So a naive "skip all bot-authored reviews" would re-break that. The no-op is specifically a bot-authored APPROVED review — an approval is terminal, there is nothing to act on, regardless of PR author. A bot CHANGES_REQUESTED/COMMENTED review with a body still has actionable content and should keep firing.
Proposed upstream fix
Add an early-exit alongside the existing issue_comment bot-skip, gated on review state so tend#166's actionable self-reviews are preserved:
# A bot-authored APPROVED review is terminal — nothing to act on. Bot reviews
# *with suggestions* on its own PR still fire (see tend#166), so gate on state,
# not just author.
if [ "$EVENT_NAME" = "pull_request_review" ] \
&& [ "$REVIEW_AUTHOR" = "dormouse-bot" ] \
&& [ "$REVIEW_STATE" = "approved" ]; then
echo "should_run=false" >> "$GITHUB_OUTPUT"; exit 0
fi
with two additions to the step env: block:
REVIEW_AUTHOR: ${{ github.event.review.user.login }}
REVIEW_STATE: ${{ github.event.review.state }}
(Generator source is generator/src/tend/workflows.py, the same file tend#166 touched.)
Ask
Per your #95 go-ahead for this family, may I file this upstream at max-sixty/tend? I've dup-checked — tend#606/#607/#166 each address a different leg, and no open issue covers the bot's-own-APPROVED-review case.
To save the round-trip in future: I can (a) treat max-sixty/tend as a standing "file directly after dup-checking" target for this no-op-session / generated-workflow-defect family and record that in running-tend so I stop asking, or (b) keep asking each time but drop this offer. Your call.
Summary
tend-mentionspins up a full (billable) agent session every time the bot leaves an empty-bodyAPPROVEDreview on a human-authored PR. The session can never produce an action — it reads the review, recognizes its own approval, and exits silently. This is a third, distinct leg of the no-op-session family you greenlit upstream in #95; it is not covered by either fix filed then (tend#606 =issue_commentleg, now shipped; tend#607 =tend-reviewself-review leg, still open). The fix lives in the upstream-owned generatedtend-mention.yaml("Do not edit this file directly"), so this asks for your go-ahead to file it at max-sixty/tend — same as #95.Surfaced by the
review-runssweep (run 27899493170).Evidence
Three occurrences in a single 24h window, one per human PR the bot approved:
pull_request_reviewAPPROVED(id 4538038926)pull_request_reviewAPPROVED(id 4538477275)pull_request_reviewAPPROVED(id 4538814194)~$0.49 for the window, and it scales linearly with how many human PRs the bot reviews — this was the highest-frequency window recorded this month (see the running tally in #123). It still fires at the current generated workflow version (tend 0.1.6).
Root cause
For a
pull_request_reviewevent theverifygate falls through to a "has the bot engaged on this PR?" heuristic:When the triggering event is the bot's own review, that review is itself counted as engagement, so
BOT_REVIEWS > 0is always true and the gate returnsshould_run=true→ a no-op session. Theissue_commentpath has an analogous early-exit (COMMENT_AUTHOR_TYPE == "Bot"→ skip); thepull_request_reviewpath has none.The tend#166 constraint (why not just filter all bot reviews)
tend#166 (closed/implemented) deliberately removed the blanket
review.user.login != botfilter so the bot can act on its own suggestion reviews on its own PRs. So a naive "skip all bot-authored reviews" would re-break that. The no-op is specifically a bot-authoredAPPROVEDreview — an approval is terminal, there is nothing to act on, regardless of PR author. A botCHANGES_REQUESTED/COMMENTEDreview with a body still has actionable content and should keep firing.Proposed upstream fix
Add an early-exit alongside the existing
issue_commentbot-skip, gated on review state so tend#166's actionable self-reviews are preserved:with two additions to the step
env:block:(Generator source is
generator/src/tend/workflows.py, the same file tend#166 touched.)Ask
Per your #95 go-ahead for this family, may I file this upstream at max-sixty/tend? I've dup-checked — tend#606/#607/#166 each address a different leg, and no open issue covers the bot's-own-
APPROVED-review case.To save the round-trip in future: I can (a) treat max-sixty/tend as a standing "file directly after dup-checking" target for this no-op-session / generated-workflow-defect family and record that in
running-tendso I stop asking, or (b) keep asking each time but drop this offer. Your call.