Merging a stack: an approval does not refresh the authority check, and a squash breaks the child's rebase nf-45n ← Beads

open priority 2 task unassigned

Twinned from https://github.com/cfsh/ninefold/issues/761 by tools/beads/import_github.py's reconcile pass.

Two things bit me merging a four-PR stack today (#739#748#752, plus #749). Neither is a bug in one tool exactly; both are interactions that cost a confusing failure and a near-miss. Filing unclaimed.

1. An approval does NOT refresh the merge-authority check, so the first merge attempt refuses with a message about the *ruleset*

@aedanpope approved #739. merge_pr.py 739 ran the full gate, passed, retargeted the child PR — and then:

``` refuse: a GitHub call failed, so the merge cannot be gated safely. X Pull request cfsh/ninefold#739 is not mergeable: the base branch policy prohibits the merge. ```

⚠️ That message names the branch ruleset, and the actual cause is a stale check run. The merge-authority check was published while the PR had no approval, says FAILURE Needs a human approval, and nothing republishes it when an approval arrives — #720 publishes it after every reviewer *sweep*, and an approval is not a sweep.

The fix is fast and already exists (#734):

```bash ./tools/pr/review_now.py <n> --reconcile-only # ~3 s, no model run ```

which re-derived SUCCESS Approved by aedanpope — human approval and let the merge through on the retry.

Why it is worth a fix rather than a note: the failure arrives *after* a full presubmit --all and the retarget, so a session pays minutes to reach a message that points at the wrong subsystem. A reader who takes it at face value goes looking at the ruleset (which is enforcement: disabled, per #633's notes) and finds nothing wrong. Options: have merge_pr.py reconcile the check itself before attempting the merge, or teach the refusal to say *"the merge-authority check predates the approval — run review_now.py <n> --reconcile-only"*.

2. A squash merge makes a stacked child's rebase conflict on every file

#739 squash-merged 10 commits into one on main. feat/probe-isolation still contained those 10 individually, so git rebase origin/main replayed each against the squashed result:

``` Could not apply 029257e... probes: import before you probe both modified: presubmit.py, probe.py, probe_all.py both added: tools/nflib/godot_import.py, tools/tests/test_nflib_godot_import.py ```

The correct move is to replay only the child's *own* commits:

```bash git rebase --onto origin/main <parent-branch-tip-BEFORE-the-merge> <child-branch> ```

⚠️ And the trap is finding that tip, because it interacts with #643: merge_pr.py had already repointed the local feat/design-005 at the merge commit, so git log parent..child listed all 14 commits rather than the 4 that were the child's. I had the pre-merge sha (68bdc63) only because it was in this session's scrollback. A fresh session would not.

Recoverable via git reflog or the PR's headRefOid from the GitHub API, but neither is obvious at the moment you need it.

⚠️ A near-miss worth recording: my rebase was chained as git rebase … && ./presubmit.py … && git push --force-with-lease. The rebase stopped on the conflict, presubmit printed nothing my grep matched, and the push still ran. It was a no-op only because a mid-rebase branch ref still points at the original tip — so the remote was untouched by luck, not by design. notes/merging.md says what to rebase a child onto (#676); it does not warn that a conflicted rebase leaves a chained push armed.

Suggestions, uncosted:

Refs #643 · Refs #676 · Refs #734 · Refs #720 · Refs #686

Dependencies

None.

Comments

No comments.

Add a comment