Skip to content

fix(ci): auto-sync opens a PR + uses merge queue, not direct push - #2234

Merged
hongmingwang-moleculeai merged 1 commit into
stagingfrom
fix/auto-sync-pr-based
Apr 28, 2026
Merged

fix(ci): auto-sync opens a PR + uses merge queue, not direct push#2234
hongmingwang-moleculeai merged 1 commit into
stagingfrom
fix/auto-sync-pr-based

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

The previous auto-sync workflow tried direct `git push origin staging` and was rejected by ruleset 15500102 (`staging-merge-queue`) on every real run. Switches to a PR-based flow that goes through the merge queue, like every other change to staging.

Why

molecule-core/staging is protected by a `merge_queue` ruleset that blocks ALL direct pushes — no bypass for org admins, no bypass for the GitHub Actions integration. The error message included:

```

  • Changes must be made through a pull request.
  • Changes must be made through the merge queue
    ```

This is by design: human PRs go through review + queue + gates before reaching staging. Auto-sync was carving an exception to that path — exactly what the ruleset prevents. The fix removes the exception.

What changes

Workflow now:

  1. Checks if main is in staging's ancestry → no-op if yes.
  2. Creates branch `auto-sync/main-` from staging.
  3. Tries `git merge --ff-only origin/main` (clean ff if staging hasn't diverged).
  4. Falls back to `git merge --no-ff` to absorb main's tip with a merge commit.
  5. Pushes the auto-sync branch.
  6. Opens PR (base=staging, head=auto-sync/main-).
  7. Enables auto-merge — the merge queue lands it once required gates pass.

Same path human PRs take. No special-snowflake bypass.

Trade-offs

Slight PR churn. Every main push that needs sync opens a tracked PR. Bounded by concurrency group + merge queue's serial processing. PRs land in order, no thundering herd.

Per-repo divergence. molecule-controlplane uses the simpler direct-push version (its staging has no merge-queue ruleset). Per-repo workflow divergence is acceptable; the invariant (staging ⊇ main) is what matters, not how it's enforced.

Loop safety preserved

GITHUB_TOKEN-authored merges don't trigger downstream workflows. The merge queue's land of the auto-sync PR does NOT fire auto-promote-staging — same loop-safety property as the direct-push version.

Idempotency

Branch name derives from main's short sha (`auto-sync/main-`), so workflow restarts on the same main push reuse the existing branch + PR rather than opening duplicates.

Test plan

  • yaml syntax valid
  • After merge: a fresh push to main triggers this workflow → opens an auto-sync PR → merge queue lands it → staging now contains main
  • Verify the auto-sync PR's CI runs the standard required gates and passes (since the merged content is already on main, gates are effectively re-running on the same SHA)

Companion to #2210

PR #2210 added this workflow originally with direct-push semantics. It worked locally but failed every real run on molecule-core. This PR is the architectural correction.

🤖 Generated with Claude Code

The molecule-core/staging branch is protected by ruleset 15500102
(name: staging-merge-queue) which blocks ALL direct pushes — no
bypass even for org admins or the GitHub Actions integration. The
prior version of this workflow attempted `git push origin staging`
and was rejected with GH013:

    ! [remote rejected] staging -> staging
    (push declined due to repository rule violations)

    - Changes must be made through a pull request.
    - Changes must be made through the merge queue

This was a real architectural mismatch: auto-sync was bypassing
the same gates everyone else goes through to land on staging,
which is exactly what the ruleset is designed to prevent.

The fix matches the org convention: the workflow now opens a PR
(base=staging, head=auto-sync/main-<sha>) and enables auto-merge.
The merge queue picks it up, runs required gates against the
merged result, and lands it. Same path human PRs take through
staging — no special-snowflake bypass.

Trade-off acknowledged

- Slight PR churn: every main push that needs sync opens a tracked
  PR. With concurrency: cancel-in-progress: false (existing) and
  the merge queue's serial processing, this is bounded — PRs land
  in order, no thundering herd.
- The previous direct-push approach worked on
  molecule-controlplane (which has no merge_queue ruleset on
  staging). That version of the workflow was correct for that
  repo's protection model. Per-repo divergence is acceptable; the
  invariant ("staging ⊇ main") is what matters, not how it's
  enforced.

Loop safety preserved

GITHUB_TOKEN-authored merges (including the merge queue's land
of this PR) do NOT trigger downstream workflow runs. So the merge
to staging from this PR doesn't fire auto-promote-staging — same
as the direct-push version.

Idempotency

The branch name is derived from main's short sha
(`auto-sync/main-<sha>`) so workflow restarts on the same main
push reuse the existing branch + PR rather than opening duplicates.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Merged via the queue into staging with commit 44a1bb0 Apr 28, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant