Merge gate must require approval for the current PR head SHA #471

Closed
opened 2026-07-07 16:30:08 -05:00 by jcwalker3 · 1 comment
Owner

Problem

A PR head can change after approval. The merge gate must not treat an old approval as sufficient unless it can prove the approval applies to the current live PR head SHA.

Observed incident (PR #424)

Field Value
PR #424
Old approved head 8b61c4b41f1b49b271ed3b99657431cf06eeda3e
Merged head 3e4b721d60e97147ba0704773cf57cd0d42cbe31
Merge commit f061fee18d8e61e2afa9641c5dbf4098b24ca792
Linked issue #407 (closed)

PR #424 was previously approved at old head 8b61c4b, then rebased to new head 3e4b721. A merge report described the PR as having a "standing APPROVED review verdict," but did not prove the approval verdict was tied to the current head SHA at merge time.

This creates a gap: code can land on master under an approval that predates the commits actually merged.

Required behavior

Merge eligibility must require an APPROVED verdict whose reviewed_head_sha matches the current live PR head SHA at merge time.

If the PR head changed after approval (push, rebase, force-push, or target-branch refresh that advances head), merge_pr must fail closed with a clear stale-approval error.

Acceptance criteria

  1. Head-tied approval — Merge eligibility requires an APPROVED verdict tied to the current live PR head SHA.
  2. Stale approval blocked — If the PR head changed after approval, merge_pr fails closed with a clear stale-approval error.
  3. Actionable error — The error reports:
    • approved SHA
    • current live SHA
    • required next action: re-review at current head
  4. Test: stale approval — Tests cover: approved-old-head → push/rebase/new-head → merge blocked.
  5. Test: fresh approval — Tests cover: approved-current-head → merge allowed.
  6. Existing gates preserved — Self-author, request-changes, mergeable, base-branch, and expected_head_sha gates remain enforced (no weakening).
  7. Workflow docs — Canonical review/merge workflow docs instruct reviewers and mergers to re-pin and re-review after any head movement.

Non-goals

  • Do not weaken existing eligibility, lease, terminal-review, or self-merge gates.
  • Do not auto-dismiss old approvals silently; surface staleness explicitly.

Related

  • PR #424 / issue #407 (reviewer PR leases — merged)
  • gitea_get_pr_review_feedback already exposes review_feedback_stale and latest_reviewed_head_sha; merge gate should enforce this, not only report it.
## Problem A PR head can change after approval. The merge gate must not treat an old approval as sufficient unless it can prove the approval applies to the **current live PR head SHA**. ### Observed incident (PR #424) | Field | Value | |---|---| | PR | #424 | | Old approved head | `8b61c4b41f1b49b271ed3b99657431cf06eeda3e` | | Merged head | `3e4b721d60e97147ba0704773cf57cd0d42cbe31` | | Merge commit | `f061fee18d8e61e2afa9641c5dbf4098b24ca792` | | Linked issue | #407 (closed) | PR #424 was previously approved at old head `8b61c4b`, then rebased to new head `3e4b721`. A merge report described the PR as having a "standing APPROVED review verdict," but did not prove the approval verdict was tied to the current head SHA at merge time. This creates a gap: code can land on `master` under an approval that predates the commits actually merged. ## Required behavior Merge eligibility must require an **APPROVED** verdict whose `reviewed_head_sha` matches the **current live PR head SHA** at merge time. If the PR head changed after approval (push, rebase, force-push, or target-branch refresh that advances head), `merge_pr` must **fail closed** with a clear stale-approval error. ## Acceptance criteria 1. **Head-tied approval** — Merge eligibility requires an APPROVED verdict tied to the current live PR head SHA. 2. **Stale approval blocked** — If the PR head changed after approval, `merge_pr` fails closed with a clear stale-approval error. 3. **Actionable error** — The error reports: - approved SHA - current live SHA - required next action: re-review at current head 4. **Test: stale approval** — Tests cover: approved-old-head → push/rebase/new-head → merge blocked. 5. **Test: fresh approval** — Tests cover: approved-current-head → merge allowed. 6. **Existing gates preserved** — Self-author, request-changes, mergeable, base-branch, and `expected_head_sha` gates remain enforced (no weakening). 7. **Workflow docs** — Canonical review/merge workflow docs instruct reviewers and mergers to re-pin and re-review after any head movement. ## Non-goals - Do not weaken existing eligibility, lease, terminal-review, or self-merge gates. - Do not auto-dismiss old approvals silently; surface staleness explicitly. ## Related - PR #424 / issue #407 (reviewer PR leases — merged) - `gitea_get_pr_review_feedback` already exposes `review_feedback_stale` and `latest_reviewed_head_sha`; merge gate should enforce this, not only report it.
jcwalker3 added the status:in-progress label 2026-07-07 23:38:05 -05:00
Author
Owner

Issue claim heartbeat

<!-- gitea-issue-claim-heartbeat:v1 --> **Issue claim heartbeat** - kind: claim - issue: #471 - branch: feat/issue-471-merge-head-approval - phase: claimed - profile: prgs-author - pr: none - blocker: none - next_action: create worktree and begin implementation
sysadmin removed the status:in-progress label 2026-07-08 00:29:19 -05:00
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#471