Repository navigation
perf(source-control): merge a stale base before push in push-branch.sh - #10568
Conversation
A push that waits in the rate gate while main moves is refused by the pre-push stale-base overlap check, costing a manual merge, re-test and re-queue each time. push-branch.sh now fetches the PR's base just before the push and, when the branch is behind it on overlapping paths (the repo's scripts/check-stale-base-overlap.sh when present, else git path lists), merges it with --no-edit, signing per the repo. A conflict aborts the merge and exits 4 without pushing. Off by default; on through sync_stale_base in docs/conventions/source-control.yaml (on for this repository) or --sync-stale-base, off through --no-sync-stale-base. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Capture the overlap and signature reads instead of piping into grep -q, which pipefail can misread; name the new HEAD after a sync merge; and say in the babysit safety rules and ready 2.5.4 what a sync merge or exit 4 means for those callers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On a machine with a global commit.gpgsign, fixture commits in
push-branch.test.sh and two babysit-prs tests signed through the
machine's signer, which failed intermittently when the pre-push check
ran the suites in parallel ("failed to write commit object", exit 128),
blocking the push. push-branch.test.sh now gives its fixtures an empty
global config, and the two babysit-prs fixtures set commit.gpgsign=false
repo-locally, as test_prune_babysit_worktrees.py already does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
claude-security-review reviewed Incremental security review of d0a420b (since 4ccabcc): no security findings. The change swaps the What I checked:
Manifest items: no critical-findings: 0 |
|
claude-review reviewed Incremental review of What changed. The setting read in Traced and correct:
Noted, not flagged. No spend beyond prepaid or subscription usage is involved, and nothing here calls for a hold. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 30d0e2e693
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… base The sync step read sync_stale_base from the pushed checkout and ran that checkout's scripts/check-stale-base-overlap.sh, so a head checked out to review or fix could switch the step on and run its own script. The setting is now read from the base repository's default branch as the clone last fetched it, and the overlap script (with the base's scripts/) is extracted from the base ref with git archive; nothing in the head is run. The base is fetched from the remote that is the PR's base repository, not the fetch remote, so a head that fetches from a fork never syncs against the fork's same-named branch; with no such remote the step is skipped with a note. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0144XNKz9sKFKYo4gQtVW78R
Lane-Activity: pr-unblock/resolve-conflicts
…' into perf/push-branch-sync-stale-base Integrates the lane's merge of main (5cf449d). config-resolution.md keeps this branch's sync_stale_base text and main's new dialect key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without --pr, sync_stale_base was read from the fetch remote's default branch before the PR's base repository was known, so a fork's copy decided the step. It is now read from the remote that is the base repository: the forge is asked for it only when some fetched remote turns the setting on, so with the setting unset everywhere the step makes no network call. The default branch is taken from the clone's fetched refs (the remote HEAD symref, else main, master or trunk), never ls-remote, on that off path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Post-merge mutation testingKilled 6, survived 2, timeout 0, no coverage 0, invalid 0, not run 0.
Surviving mutants
The run's summary has the full report. |
No related issue: push churn measured on #10491 (about 75 min, 3 stale-base refusals)
Summary
A push waits in the rate gate (
gate.sh run KEY -- <push>) for minutes, sometimes over an hour while the token breaker is tripped. Meanwhile main moves, and the pre-push hook (scripts/check-affected.shrunningscripts/check-stale-base-overlap.sh) refuses the push as "STALE BASE with overlapping paths". Each refusal costs a manual merge of main, a re-test and a re-queue: #10491 took about 75 minutes and 3 refusals to land one push, and #10498 was refused once the same way.gate.shstays a pure rate gate, so the fix is in source-control's push helper, which runs inside the gate after admission, when main is current.Fix
plugins/source-control/skills/pull-request/scripts/push-branch.shgains a sync-stale-base step on the operator path, just before the push:--pr's existinggh pr viewread, now withbaseRefName; otherwisegh pr view <branch>; with no PR yet, the fetch remote's default branch. Thengit fetchit from the fetch remote.scripts/check-stale-base-overlap.sh --check <remote>/<base>when that file exists (exit 1 merges, 0 does not, anything else skips with a note). Otherwise it is the paths both sides changed since the merge-base, read with git.git merge --no-edit, never a rebase. Git signs it itself whencommit.gpgsignis true;-Sis added when HEAD is signed. Nothing is hard-coded.git merge --abortand exits 4, pushing nothing.gate.shuses 0 to 3 itself, so 4 stays distinct throughgate.sh run.The step is skipped with a stderr note when the base cannot be read or fetched, the branch is checked out in no worktree, tracked files have uncommitted edits, or a merge is in progress.
--checkand lane pushes never sync.Config: a new team key
sync_stale_base(boolean) indocs/conventions/source-control.yaml, read from the checkout throughlib/convention-key.sh, added to the schema andreference/config-resolution.md. It defaults tofalsebecause an unrequested merge commit in a consumer's branch is a behavior change, and without a refusing hook it buys little. This repository turns it on.--sync-stale-baseand--no-sync-stale-baseoverride it for one push.The
create(§2.4.1) andready(2.5.4) references and babysit-prs' safety rules describe the merge and exit 4.Verification
push-branch.test.sh: 170 passed, 0 failed. New cases cover: current base (fetch, no merge, push); stale base with no overlap (no merge); overlap (two-parent merge, first parent the old tip, second the base tip, pushed, unsigned in an unsigned repository);commit.gpgsign=trueand a signed tip withgpgsignunset (merge signed); conflict (exit 4, noMERGE_HEAD, HEAD unchanged, nothing pushed); disabled by no config, by--no-sync-stale-baseand by--check(no fetch);--sync-stale-basewith no config; a stacked PR base; the repository overlap script winning over git; a dirty tree. Before the implementation, 17 of the new checks failed.babysit-prs/reference/safety.md. The helper mergedorigin/main(merge commit30d0e2e693, signed, first parent the old tip), and the pre-push hook passed on the merged tree.commit.gpgsign, fixture commits went through the machine's signer. That signer failed intermittently when the pre-push check ran suites in parallel (failed to write commit object, exit 128; reproduced with 16 concurrent commits, 1 failed), and the push was blocked.push-branch.test.shnow gives its fixtures an empty global config. The two babysit-prs fixtures that failed setcommit.gpgsign=falseper repository, astest_prune_babysit_worktrees.pyalready does.check-changed-skills.shthen passed 5 runs out of 5.scripts/check-fixture-git-isolation.sh: OK.gh-forge.test.sh: 34 passed.check-convention-yaml.shvalidates, and its test passed 45. babysit-prs Python tests: 3255 passed. shellcheck and shfmt are clean.Related
🤖 Generated with Claude Code