Skip to content

feat(ci): auto-sync main → staging to keep staging-as-superset invariant - #2209

Merged
HongmingWang-Rabbit merged 1 commit into
stagingfrom
feat/auto-sync-main-to-staging
Apr 28, 2026
Merged

feat(ci): auto-sync main → staging to keep staging-as-superset invariant#2209
HongmingWang-Rabbit merged 1 commit into
stagingfrom
feat/auto-sync-main-to-staging

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

Eliminates the bridge-PR-thrash class that bit us twice today (#2202, #2205). Whenever main moves, staging absorbs the new tip automatically — no more manual gh pr update-branch round-trips on follow-up PRs.

Mechanism

Triggered on every `push: branches: [main]`:

  1. No-op case (steady state): `origin/main` is already in staging's ancestry. Workflow logs and exits. This is the common case after `auto-promote-staging.yml` ff-advanced main from staging.

  2. Manual main merge case (the bug we hit twice today): main has a merge commit not on staging. Try ff first; if staging hasn't diverged it succeeds and staging fast-forwards to main.

  3. Diverged case (staging has in-flight feature work main doesn't): create a merge commit `chore: sync main → staging (auto)` so staging absorbs main's tip while keeping its own history.

  4. Push staging.

Loop safety

Pushing synced staging triggers auto-promote-staging.yml, which ff-pushes staging to main. main now equals staging; that push is a no-op ref-update so no push event fires → auto-sync doesn't re-trigger. Bounded.

Conflict handling

If `merge --no-ff main` hits conflicts (staging and main diverged with incompatible changes), workflow fails with a clear summary pointing to manual resolution. Shouldn't happen in practice — conflicts indicate a direct main hotfix touching the same code as in-flight staging work, which is itself an anti-pattern (hotfixes should land on staging first).

Test plan

  • yaml syntax valid
  • After merge: any future direct main push (e.g. another manual bridge, or a CEO direct merge) triggers this workflow and updates staging within ~30s
  • After merge: the next staging → main PR no longer needs `gh pr update-branch` because staging always contains main

Out-of-scope (track separately)

🤖 Generated with Claude Code

Background

`auto-promote-staging.yml` advances main via `git merge --ff-only`
+ `git push origin main` — clean fast-forward, no merge commit. But
manual `staging → main` merges via the GitHub UI / API create a merge
commit on main that staging doesn't have. The next `staging → main`
PR then evaluates as "BEHIND" because staging is missing that merge
commit, requiring a manual `gh pr update-branch` round-trip.

This pattern bit twice on 2026-04-28 (PRs #2202 and #2205, both
manual bridges to land pipeline fixes themselves). Each needed
update-branch + re-CI before they could merge. Annoying and
avoidable.

What this workflow does

Triggered on every push to main (regardless of source: auto-promote,
UI merge, API merge, direct push):

  1. Check whether main is already in staging's ancestry. If yes,
     no-op — auto-promote-staging keeps them aligned via ff push,
     and the no-op case is the steady state.

  2. If not (manual merge commit on main, or direct main hotfix):
     try `git merge --ff-only origin/main` first. Works when staging
     hasn't diverged with its own commits.

  3. If ff fails (staging has its own in-flight feature work):
     `git merge --no-ff origin/main -m "chore: sync main → staging"`.
     Absorbs main's tip while keeping staging's own history.

  4. Push staging.

Loop safety

Pushing the synced staging triggers auto-promote-staging.yml, which
checks gates on staging's new tip and, if green, ff-pushes staging
to main. Since staging now ⊇ main, the resulting push to main is
either a no-op (no ref change → no push event fires → auto-sync
doesn't re-trigger) or advances main further. In the latter case
auto-sync fires once more, sees main already in staging's ancestry,
no-ops. Bounded.

Conflict handling

If the merge step hits conflicts (staging and main diverged with
incompatible changes), the workflow fails with a clear summary
pointing to manual resolution. This shouldn't happen in practice —
staging is the integration branch; conflicts indicate a direct main
hotfix touching the same code as in-flight staging work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@HongmingWang-Rabbit
HongmingWang-Rabbit added this pull request to the merge queue Apr 28, 2026
Merged via the queue into staging with commit 08c93e2 Apr 28, 2026
21 checks passed
@HongmingWang-Rabbit
HongmingWang-Rabbit deleted the feat/auto-sync-main-to-staging branch April 28, 2026 21:53
HongmingWang-Rabbit pushed a commit that referenced this pull request Jun 12, 2026
… 4 to 32 (#2204)' (#2209) from fix/2204-liveness-probe-max-tokens into main
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