fix(mention): skip a third party's content-free approval - #955
fix(mention): skip a third party's content-free approval#955tend-agent wants to merge 2 commits into
Conversation
tend-agent
left a comment
There was a problem hiding this comment.
The gate itself reads correctly: $INLINE is populated a few lines above, an empty review-comments array leaves it the empty string, and approved + empty body + zero inline comments is genuinely terminal. Regtest snapshots are all updated and the suite is green locally (420 passed).
One gap in the new test. Its stated job is to pin the load-bearing narrowings, but the property that actually makes [ -z "$INLINE" ] mean "zero inline comments" is positional — the gate has to sit below INLINE=$(gh api ... /reviews/$PAYLOAD_ID/comments ...). The condition-equality assert doesn't encode position, and the existing ordering assert (< BOT_REVIEWS=$() still passes if the gate is hoisted above the fetch. That hoist is a plausible future edit, since the bot-authored approval gate deliberately sits before the fetch and the comment there advertises it as "one API call cheaper" — and it fails silently: an unset $INLINE reads as empty, so every third-party approval carrying inline nits gets skipped, which is exactly the case this gate's comment says must fire.
`[ -z "$INLINE" ]` only means "zero inline comments" below the fetch that populates it. That property is positional, so the condition-equality assert does not cover it, and the existing BOT_REVIEWS ordering assert still passes if the gate is hoisted above the fetch — a plausible edit, since the bot-authored approval gate deliberately sits before it to save an API call. Hoisted, $INLINE is unset, reads as empty, and every third-party approval carrying inline nits is skipped.
Problem
tend-mentionstarts a full billable session every time someone other than the bot approves a PR with an empty review body and no inline comments. The session reads the PR, finds nothing addressed to it, and exits silently. It can only ever no-op: a bareAPPROVEDasks for nothing, and the bot is barred from merging, so there is no role left for it to act in.verifyhas two terminal-review gates and both key onREVIEW_AUTHOR: the empty-bodyAPPROVEDgate (#747) and the synthetic reply-container gate (#849/#866). A third party's approval matches neither, so it falls through to thePR_AUTHOR == botshort-circuit on a bot-authored PR — or toBOT_REVIEWS, which counts the triggering review itself — andshould_run=trueis unconditional. Structural: there is no decision point, so the same shape recurs every time a human approves one of the bot's PRs without typing anything.Distinct from the three issues already open or closed on this path. #747 fixed the bot's own empty-body approval; #866 targets the synthetic empty-body
COMMENTEDcontainer GitHub creates for an inline reply; #915/#916 target the bot's own content-bearing review on someone else's PR. All three are author-keyed by design; this is the residual their author-keying leaves behind, and it was named as such in the evidence log two days before this run.Evidence
Three occurrences on
PRQL/prql, all traced to the review record rather than inferred from the run:kgutwinAPPROVED, empty body, no inline commentsvanillajonathan4914418538,APPROVED, body length 0,pulls/6185/commentsemptykgutwin4916991960,APPROVED, body length 0, zero inline commentsThe third one's session log says why it published nothing, in five tool calls: "The trigger was a plain approval (
APPROVED, empty body, no inline comments) from @kgutwin on PR #6186, which is already MERGED. No questions, no requested changes, no unaddressed comments anywhere on the thread. Per the review-response rules, a plain approval gets no reply, so I'm not posting anything." The model reaches the right verdict every time; the cost is that it has to boot to reach it.Solution
A third clause on the same gate chain, inside the
pull_request_reviewblock and after the@-mention scan, so a mention buried in an inline comment still summons the bot:It costs no extra API call —
$INLINEis already fetched a few lines above for the mention scan.Two narrowings, both load-bearing:
approved, not any state. A human's reply to one of the bot's review threads also arrives as an empty-body review container, butCOMMENTED. Widening the state here would silence the bot on every human reply to its own threads — the same traptest_mention_skips_bot_reply_containerpins from the author side, sincepull_request_review_commentsubscribes toeditedonly.$INLINEempty, not reply-only. An approval whose nits live in inline comments is a request addressed to the PR's author, and on a bot-authored PR that is a role the bot has to act in. Only a review with nothing in it anywhere is terminal.The two author-keyed gates stay as they are: the bot's own empty-body
APPROVEDis skipped before the$INLINEfetch, which keeps that path one API call cheaper.Gate assessment
Evidence log: https://gist.github.com/192514ea2c36586f9b7f842a482d62ab (
review-reviewers evidence: PRQL/prql 2026-08), where this finding was recorded at one occurrence on 2026-08-10 and at two on 2026-08-12 before crossing here.Testing
test_mention_skips_third_party_bare_approvalcompares the whole gate condition with whitespace normalized, so an author clause added later — or the$INLINEclause dropped — fails on equality rather than sliding past anincheck. It fails onmain(ValueError: substring not found). The fourmentionregtest snapshots are updated. Full generator suite: 420 passed.