ci: warn before a base merge cancels a PR's running CI

Merged
TE
16d ago
+365-2

Summary

A push to a PR cancels every job still running on its old head. On 2026-10-21, re-pushes that merged the base cut 295 of the 444 Mac runner-minutes lost to cancelled jobs in 55 minutes (leo-workspace research/cmux-ci-repush-waste-2026-10-21.md). next-autoland now waits for running checks before its base merge (teamleaderleo/leo-workspace#654). This PR covers lanes.

scripts/ci/base_merge_warning.py warns and never refuses:

  • pre-push hook: when the pushed commits include a clean merge of feat-cmux-next or main (second parent on the base, tree equal to git merge-tree of the parents) and the old head still has check runs queued or running.
  • Claude Code PreToolUse(Bash) hook (.claude/settings.json, scripts/ci/base-merge-warning-hook.sh): on gh api .../pulls/N/update-branch while the PR's head has checks running, it adds the warning as context. Any other command exits in bash without starting Python.

Both stay quiet when GitHub can't be read (15 s timeout per call). The advice they print: merge the base once, right before landing, or when GitHub says the PR conflicts.

tests/test_base_merge_warning.py (linux-guard, run in cmux-next.yml's checks job next to the pre-push gate test) builds a fixture repo with a fake gh and covers each case: a clean base merge while checks run, the same with nothing running, an ordinary commit, a merge with extra changes, pushes to the base or a new branch, unreadable GitHub, and the hook with and without update-branch.

Changelog

none

Observed / Not run

  • Observed: py_compile of the script and bash -n of both shell scripts pass.
  • Not run: the new test. Test runs are blocked on this Mac, so CI's checks job is its first run.

Agent session: cosmic-gray

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.


Summary by cubic

Warns before a base merge push cancels a PR's running CI. A base merge re-push cut 295 Mac runner-minutes on 2026-10-21, so a base merge now triggers a warning when the old head still has checks queued or running.

  • The pre-push hook runs scripts/ci/base_merge_warning.py, which flags clean base merges (second parent on feat-cmux-next or main, tree equal to git merge-tree) and reports the running-check count on the old head. It reads only the branch's own merges, skipping the base's own merge commits, and stops at the first match.
  • A Claude Code PreToolUse(Bash) hook (run from CLAUDE_PROJECT_DIR) adds the same warning as context to gh api .../pulls/N/update-branch, gh pr update-branch N, and {owner}/{repo} placeholder calls; any other Bash command exits without starting Python.
  • Both paths never refuse a push and stay quiet when GitHub can't be read (15 s timeout per call).
  • tests/test_base_merge_warning.py covers each case with a fixture repo and fake gh (the fixture base has its own merge commit), and runs in CI's checks job; installer-copying tests pick up the new script too.