Skip to content

fix(bump-callers): reuse one open PR per repo via a stable branch (BE-3882)#44

Merged
mattmillerai merged 3 commits into
mainfrom
matt/be-3882-stable-bump-branch
Jul 21, 2026
Merged

fix(bump-callers): reuse one open PR per repo via a stable branch (BE-3882)#44
mattmillerai merged 3 commits into
mainfrom
matt/be-3882-stable-bump-branch

Conversation

@mattmillerai

Copy link
Copy Markdown
Contributor

ELI-5

When we update a shared workflow here, a bot goes to every repo that uses it and opens a PR to point at the new version. The bug: it named each PR's branch after the new version's ID, so every update opened a brand-new PR and left the old ones sitting open — a growing pile where you couldn't tell which pin was current.

Now the bot uses one fixed branch name per repo (ci/bump-<tag>). On the next update it reuses that same branch — rebuilding it fresh from the repo's current main and refreshing the existing PR's diff/title/body — instead of opening another. So there's at most one open bump PR per repo per workflow at any time, always showing the latest pin.

What changed

.github/bump-callers/bump-callers.sh (the one shared script behind both the bump-cursor-review-callers and bump-agents-md-callers fleets):

  1. Stable branchBRANCH="ci/bump-${TAG}" (dropped the ${SHORT} suffix). The SHA now lives only in the commit/title/body.
  2. Rebuild from the tip every run — create the branch at the caller's current default-branch tip, or PATCH-force it back to the tip if it already exists, then apply the single file-pin change. The PR diff is always a clean single "bump to @short" commit — no accumulated stale commits, no drift if the caller's main moved.
  3. Update-in-place vs creategh pr list --head "$BRANCH" --state open decides: if a bump PR is already open, gh pr edit refreshes its title/body (they embed ${SHORT}) — no second PR. If none is open (first bump, or the prior one merged/closed since last run), gh pr create opens a fresh single one.

Acceptance criteria

  • ✅ At most one open bump PR per (repo, workflow) at any time.
  • ✅ A subsequent bump updates that PR's branch + title/body rather than opening another.
  • ✅ If the open PR was merged/closed since last run, the next bump opens a fresh single one (the --state open check falls through to create; a residual branch is force-reset first).
  • ✅ PR diff stays a clean single "bump to @short" change vs the caller's current default branch.
  • ✅ Fix lives in the shared bump-callers.sh, so it applies to both the cursor-review and agents-md dispatchers.

Tests

bash .github/bump-callers/tests/test_bump_callers.sh + shellcheck -x33/33 pass. Added coverage for the new update-in-place path (open PR is edited, not re-opened) and asserted the create path does no edit when no PR is open. The gh stub gained pr list/pr edit/PATCH handling and a STUB_OPEN_PR toggle.

Judgment calls / notes

  • Force-reset of the bump branch is intentional and safe: the target is always a bot-owned ci/bump-* branch, so the only thing discarded is the prior bump commit — exactly what we're replacing. It does refresh an open PR's diff out from under any in-progress review, but that's the desired "update to latest SHA" behavior for an automated bump PR.
  • Labels are not re-added on the update-in-place path — the fleet label is applied at PR creation and persists; the ticket only calls for refreshing title/body on update.
  • --field force=true relies on gh's typed --field form sending a JSON boolean (same --field form the script already uses); confirmed against the refs PATCH API.

…-3882)

The dispatcher embedded the new short-SHA in the branch name
(ci/bump-<tag>-<short>), so every bump minted a unique branch and thus a
brand-new PR in each caller repo, leaving the prior bump PRs open. The stack
made it unclear which pin was current.

Make the branch stable per (repo, TAG) — ci/bump-<tag> — and update it in
place: each run rebuilds the branch from the caller's current default-branch
tip (a clean single-commit "bump to @short" diff), then, if a bump PR is
already open for that branch, refreshes its title/body to the new SHA instead
of opening another; a fresh PR is opened only when none is open (first bump,
or the prior one merged/closed since the last run). Result: at most one open
bump PR per (repo, workflow) at any time. Applies to both the cursor-review
and agents-md fleets via the shared script.

Adds test coverage for the update-in-place path (open PR is edited, not
re-opened) and the create path (no edit when no PR is open).
@mattmillerai mattmillerai added agent-coded Authored by the agent-work loop cursor-review Multi-model cursor review labels Jul 21, 2026
@mattmillerai
mattmillerai marked this pull request as ready for review July 21, 2026 03:15
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b3cba1a6-0634-4943-a045-b349a7f6387a

📥 Commits

Reviewing files that changed from the base of the PR and between b47ac21 and f08a97e.

📒 Files selected for processing (5)
  • .github/bump-callers/README.md
  • .github/bump-callers/bump-callers.sh
  • .github/bump-callers/tests/test_bump_callers.sh
  • .github/workflows/bump-agents-md-callers.yml
  • .github/workflows/bump-cursor-review-callers.yml

📝 Walkthrough

Walkthrough

The caller bump process now operates per repository, reuses stable branches and open pull requests, distinguishes missing files from fetch failures, and serializes each caller fleet’s workflow runs.

Changes

Caller bump consolidation

Layer / File(s) Summary
Repository-level bumping
.github/bump-callers/bump-callers.sh, .github/bump-callers/README.md
Caller entries are grouped by repository, files are committed on stable branches, and existing pull requests are updated instead of duplicated.
Bump behavior validation
.github/bump-callers/tests/test_bump_callers.sh
Tests cover multi-file repositories, duplicate entries, missing and failing fetches, partial pins, already-pinned files, and pull-request selection.
Fleet concurrency controls
.github/workflows/bump-agents-md-callers.yml, .github/workflows/bump-cursor-review-callers.yml
Both workflows serialize runs with fixed concurrency groups and retain in-progress executions.

Sequence Diagram(s)

sequenceDiagram
  participant Workflow
  participant bump_repo
  participant ContentsAPI
  participant PullRequestAPI
  Workflow->>bump_repo: Group caller entries by repository
  bump_repo->>ContentsAPI: Fetch files at default-branch tip
  ContentsAPI-->>bump_repo: Return contents or fetch status
  bump_repo->>PullRequestAPI: Reset branch and commit updated files
  bump_repo->>PullRequestAPI: Update existing PR or create one
Loading
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch matt/be-3882-stable-bump-branch
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch matt/be-3882-stable-bump-branch

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Cursor Review — Consolidated panel

Triggered by @mattmillerai.

Found 7 finding(s).

Severity Count
🔴 Critical 1
🟡 Medium 5
🟢 Low 1

Panel: 6/8 reviewers contributed findings.

Reviewers that did not contribute: kimi-k2.5:adversarial (empty), kimi-k2.5:edge-case (empty)

Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh
Comment thread .github/bump-callers/bump-callers.sh
Comment thread .github/bump-callers/tests/test_bump_callers.sh Outdated
Comment thread .github/bump-callers/bump-callers.sh
…or (BE-3882)

Harden the stable-branch bump PR reuse from the review panel:

- Existing-PR lookup: use `.[0].number // empty` (a bare `.[0].number`
  prints the literal `null` on an empty list, so the first bump for a
  repo — and every bump after the prior PR merged/closed — ran
  `gh pr edit null` and failed the caller). Also exclude
  cross-repository PRs (`isCrossRepository == false`): `--head` matches
  by branch name across forks, so with the now-predictable branch name
  an attacker could pre-open a fork PR the bot would stamp instead of
  bumping the real caller.
- Create path: `return 1` on a genuine `gh pr create` failure. The
  update-in-place path already handles an open PR, so reaching create
  means none exists and a failure is a real miss — record it in FAILED
  instead of reporting success.
- Serialize each fleet with a `concurrency:` group (cancel-in-progress:
  false) so overlapping runs can't race the shared stable branch; the
  newest pending run wins so the latest SHA is committed.
- Tests: the gh stub now faithfully models `gh pr list --json --jq` by
  running the real jq over the JSON gh would return, so the no-open-PR
  case reproduces production instead of masking it; add a fork-PR decoy
  regression case.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@mattmillerai

Copy link
Copy Markdown
Contributor Author

🤖 The reviews loop filed Linear follow-up ticket(s) for review thread(s) deferred as out of scope for this PR:

  • BE-3896 — bump-callers: handle multiple files per repo on the shared stable branch

…(BE-3896) (#45)

* fix(bump-callers): commit all of a repo's files onto one bump branch (BE-3896)

Group CALLERS entries by repo before the bump loop and reset the stable
branch ONCE per repo, then commit each of that repo's files onto it with
successive PUTs (each carrying that file's own blob SHA). The old per-entry
loop reset the branch before every file, so a second same-repo entry's reset
discarded the first entry's commit and the PR shipped only the last file while
every entry reported success — a silent partial bump. Only affects repos that
appear more than once in a caller list; single-file repos are unchanged.

The test stub now models the one bump branch's committed file set (a ref
reset truncates it, a PUT appends), and a new same-repo two-file case asserts
BOTH files land on the branch — it fails against the pre-fix script.

* fix(bump-callers): harden per-file staging against partial/erroneous bumps (BE-3896)

Address cursor-review panel findings on the multi-file-per-repo bumper:

- Distinguish a genuine 404 (per-file skip) from any other fetch error
  (auth/rate-limit/5xx/network); a transient error now fails the whole repo
  instead of silently shipping a PR that omits the un-fetched file.
- Resolve the default-branch tip (MAIN_SHA) up front and pin every Pass-1 blob
  fetch to that immutable SHA, closing a TOCTOU race with a moving default branch.
- De-duplicate staged files by path so a repo listed twice for the same file
  commits it once (a second PUT with a now-stale blob sha would 409 the repo).
- Skip an already-pinned file by comparing rewritten-vs-original content instead
  of grepping for NEW_SHA anywhere, which also repairs a half-bumped file.
- Anchor the 40-hex SHA rewrite to the github-workflows / workflows_ref pin
  contexts so a full-SHA pin of another action (actions/checkout@<sha>) is not
  clobbered.
- Collect a caller entry's label only once its file is confirmed staged, so a
  skipped entry's label never lands on the real bump PR.
- Exact-match label de-dup (GitHub label names may contain the `|` sentinel).

Adds functional tests for each: 404-skip vs transient-fail, same-file de-dup,
non-github-workflows pin preservation, half-bump repair, and already-pinned skip.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@mattmillerai
mattmillerai merged commit 3160702 into main Jul 21, 2026
3 of 4 checks passed
@mattmillerai
mattmillerai deleted the matt/be-3882-stable-bump-branch branch July 21, 2026 17:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent-coded Authored by the agent-work loop cursor-review Multi-model cursor review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant