fix(weekly): don't trust a re-anchored approval on a rebased dependency PR - #890
fix(weekly): don't trust a re-anchored approval on a rebased dependency PR#890tend-agent wants to merge 4 commits into
Conversation
tend-agent
left a comment
There was a problem hiding this comment.
Checked the mechanism against the three PRs in the description: PRQL/prql#6158's lone approval is stamped 2026-08-07T06:09:36Z against cc020720, a commit the head_ref_force_pushed at 07:40:18Z created — the new filter drops it, and the two controls still skip. review and weekly are the only two anchor-comparison sites in the plugin, so with #884 that closes the set.
One gap the diff leaves open: only the approve path resolves a re-anchored approval. Step 2's items 4 and 5 — "If CI is failing, comment with the failure summary and skip" and "If a major version bump, comment noting it needs manual review and skip" — never reach the guard, and both are reachable precisely because a rebase changed something. So a dependency PR that was approved, then rebased into red CI, gets a failure comment while the pre-rewrite APPROVED stays the bot's latest review and the PR still reads as bot-approved — the state the title is about. Either dismiss the pre-rewrite approval on those paths (reviews/$REVIEW_ID/dismissals, as #884 does for review), or say in the body that it's deliberately a follow-up.
|
Good catch — dismissing, not deferring. Pushed as Items 4 and 5 now carry an item 6 that pulls the newest Resolving against the same three PRs the description uses: Re-running is a no-op: dismissal moves the state to Filter output |
tend-agent
left a comment
There was a problem hiding this comment.
Item 6 closes the gap the last review flagged. Re-ran both filters live against the three PRs in the description: #6158 selects 4880377370 for dismissal and yields no surviving approval for the item 3 guard; #6157 and #6156 select nothing and keep their approvals anchored at 69d5b27c / 9b6a2e78. The issues/<n>/timeline call returns head_ref_force_pushed without a preview header, and item 3 and item 6 are exact complements (> $fp / < $fp), so no approval falls through both. #882 touches the adjacent else branch in this same block but git merge-tree merges the two cleanly.
Two things on item 6's snippet, both inline.
The selector orders select before last, so it picks the newest stale approval rather than testing whether the newest approval is stale. Given [APPROVED@06:09 (pre-rewrite), APPROVED@08:00 (post-rewrite)] and a rewrite at 07:40, it returns the 06:09 id — dismissing a review that a valid post-rewrite approval already superseded, while the 08:00 approval that determines the PR's state stays untouched. Swapping the order returns empty there and is unchanged on all three verification PRs.
The dismissal message says "re-reviewing", but items 4 and 5 are the comment-and-skip paths — nothing re-reviews. A maintainer reading the dismissal on a dependabot PR is told a review is coming that never arrives.
|
Both fixed in Selector order. Dismissal message. Now Selector comparison |
tend-agent
left a comment
There was a problem hiding this comment.
Both findings from the last review are cleared in f3a5bed. I re-ran the reordered selector rather than take the claim on trust — it returns the id on a lone pre-rewrite approval, empty when a post-rewrite approval supersedes it, empty on an empty review list, and empty when $fp is unset. The . != null the commit added beyond the suggested form is what keeps that empty-list case from reaching .submitted_at.
One thing worth recording since the two snippets now look inconsistent: item 3's LAST_APPROVAL_SHA filter keeps the original select-then-last order, and that is not a second instance of the same bug. submitted_at is monotonic across the REST reviews list, so item 3's .submitted_at > $fp predicate selects a suffix — last of the suffix is last of the whole list whenever either is non-empty, making the two orders equivalent there. Item 6's < $fp selects a prefix, which is precisely why the order changed the answer there and not here.
Self-authored, so this stands as a COMMENT — no approval is coming from this reviewer.
weekly's dependency-PR step skips approving whenLAST_APPROVAL_SHA == HEAD_SHA. A force-push doesn't just move the head — GitHub re-points the prior review's commit anchor at the new head, so after a rebase that comparison reads true for a commit the bot never read. The PR is left carrying anAPPROVEDit never earned, and the one step that would have re-checked it declines to run.Dependency PRs are the population tend rewrites on purpose:
nightlyposts@dependabot recreateand ticks renovate'srebase-checkon conflicted bot PRs, both of which force-push.Observed
PRQL/prql#6158(dependabot,js-yamlbump).prql-botapproved at 06:09:36Z; dependabot rebased at 07:40:18Z. Running the current snippet against it now:cc020720was created 90 minutes after that approval.Fix
Take the newest
head_ref_force_pushedoff the timeline and drop approvals older than it, mirroring the probe #884 adds toreview's three anchor sites. Switching fromgh pr view --json reviewsto the REST endpoint is what makes the filter expressible:submitted_atisn't in the GraphQL projection, andgh api --jqtakes no--arg, so the comparison pipes tojq. Note the field rename that comes with it — REST carries.commit_id, not.commit.oid.The equality test also gains an
-nguard: with no surviving approval both sides can now be empty, and[ "" = "" ]would skip.Fixing the approve path alone would leave the stale
APPROVEDstanding on the two paths that don't reach it — step 2's "CI is failing, comment and skip" and "major version bump, comment and skip". Both are reachable precisely because a rebase changed something, so a rebased-into-red dependency PR would get a failure comment while still reading as bot-approved. A new item 6 dismisses any approval older than the newest rewrite on those paths, using the samereviews/$REVIEW_ID/dismissalscall #884 givesreview. It's idempotent — a dismissed review reportsDISMISSED, so the filter stops matching it.Verified live
#6158#6157#6156The two controls confirm the redundant-approval suppression the guard exists for is intact; only the rewritten case flips.
The dismissal filter resolves against the same three:
#6158selects review4880377370(prql-bot,APPROVED,submitted_at06:09:36Z,commit_idcc020720— the post-rewrite head, re-anchored), and both controls select nothing.Flagged in the review of #884 as a separate concern from that diff, which patches
reviewonly.