Skip to content

tend-mention: no-op session on bot's own APPROVED review of human PRs (upstream filing request) #168

Description

@dormouse-bot

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions