Summary
When a PR goes approve → request_changes → fixes → clean re-review, cr cannot post the re-approval. Its "already approved" host-state check matches any APPROVED review object ever posted by its identity — ignoring that a later CHANGES_REQUESTED superseded it — while GitHub branch protection (require approval of latest push) does not count that stale approval. The two systems deadlock and no cr flag resolves it.
Reproduction (private repo, branch protection requiring approval of latest push; cr 0.10.x, GitHub provider)
cr review → APPROVED at commit A.
- Push commit B with material changes;
cr review --rerun → CHANGES_REQUESTED at B.
- Fix findings in commit C; resolve threads;
cr review --rerun → the run's rollup verdict is review_event: approve (zero findings), but the posted event is COMMENT.
- GitHub reviewDecision: CHANGES_REQUESTED (later REVIEW_REQUIRED once the stale request-changes reviews are dismissed). Branch protection blocks merge.
- Plain
cr review: early-exits "review already approved" (the stale APPROVED object from step 1).
--rerun: runs fully, rollup approve, posts COMMENT again. --retry-posts: "no live run has required pending or failed_terminal actions" (the comment post is considered complete). cr data purge + plain review: same early exit — so the check is host-state, not local.
- The approval-override fast-path can't fire either: its precondition is "no existing approval is present," and the stale APPROVED object satisfies "present."
Only manually dismissing every stale APPROVED review object un-wedges it — after which the plain review's override fast-path worked exactly as documented (classifier approved the override request, approval posted at head, merge unblocked).
Expected
The "already approved" check (and the override fast-path's existing-approval precondition) should consider only the identity's currently-effective review — an approval superseded by a later CHANGES_REQUESTED from the same identity is not an approval — or the poster should submit an approval whenever the current rollup verdict is approve and the effective decision is not APPROVED.
Impact
Every multi-round PR that ever regresses from approval hits this; the workaround (dismissing stale review objects via the GitHub API, one per stale approval) is manual, non-obvious, and easy to get wrong.
Summary
When a PR goes approve → request_changes → fixes → clean re-review, cr cannot post the re-approval. Its "already approved" host-state check matches any APPROVED review object ever posted by its identity — ignoring that a later CHANGES_REQUESTED superseded it — while GitHub branch protection (require approval of latest push) does not count that stale approval. The two systems deadlock and no cr flag resolves it.
Reproduction (private repo, branch protection requiring approval of latest push; cr 0.10.x, GitHub provider)
cr review→ APPROVED at commit A.cr review --rerun→ CHANGES_REQUESTED at B.cr review --rerun→ the run's rollup verdict isreview_event: approve(zero findings), but the posted event is COMMENT.cr review: early-exits "review already approved" (the stale APPROVED object from step 1).--rerun: runs fully, rollup approve, posts COMMENT again.--retry-posts: "no live run has required pending or failed_terminal actions" (the comment post is considered complete).cr data purge+ plain review: same early exit — so the check is host-state, not local.Only manually dismissing every stale APPROVED review object un-wedges it — after which the plain review's override fast-path worked exactly as documented (classifier approved the override request, approval posted at head, merge unblocked).
Expected
The "already approved" check (and the override fast-path's existing-approval precondition) should consider only the identity's currently-effective review — an approval superseded by a later CHANGES_REQUESTED from the same identity is not an approval — or the poster should submit an approval whenever the current rollup verdict is approve and the effective decision is not APPROVED.
Impact
Every multi-round PR that ever regresses from approval hits this; the workaround (dismissing stale review objects via the GitHub API, one per stale approval) is manual, non-obvious, and easy to get wrong.