mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
feat(ci): Mergify merge queue + manual-train fallback runbook (WS3.4/WS3.2) (#7112)
* feat(ci): Mergify merge queue for release branches + manual-train fallback runbook (WS3.4/WS3.2) D5 final decision (owner, 2026-07-13, post vendor research): Mergify OSS plan — free/unlimited for the public repo, with the two features the volume demands (85-100 active authors/month, 300+ PRs/week peaks, ONE merger): batching + automatic bisection of red batches (log2(N) vs N revalidations). Proven at larger scale by NixOS/nixpkgs. - .mergify.yml: queue for base ~= release/vX.Y.Z (the wildcard GitHub's native queue cannot do); entry ONLY via the owner-applied 'queue' label AFTER the pre-merge star gate (the label IS the approval — Mergify executes, never decides); merge_conditions '#check-failure=0' + '#check-pending=0' respect the path-filtered fast-gates; squash keeps one-commit-per-PR history; label auto-removed after merge. Freeze/cross-session guardrails documented in-file. - docs/ops/MERGE_TRAIN.md (WS3.2): the manual merge-train codified as the FALLBACK runbook (batch -> validate once -> bisect halves on red) + the tiering rationale (per-PR fast-gates, per-tip continuous release-green, per-release full matrix — nothing validated less, just per batch not per PR). - 'queue' label created in the repo. Config validated (YAML parse); Mergify's own config check runs on this PR. * fix(ci): mergify queue must not fail open — require the always-on Merge-integrity check as affirmative success
This commit is contained in:
committed by
GitHub
parent
00bdefcf0e
commit
9fa54e85e4
55
.mergify.yml
Normal file
55
.mergify.yml
Normal file
@@ -0,0 +1,55 @@
|
||||
# Mergify merge queue — WS3.4/D5 of the v3.8.49 quality/velocity master plan.
|
||||
#
|
||||
# WHY: ~85-100 active PR authors/month and 300+ PRs/week peaks, all merged by ONE
|
||||
# identity. The manual merge-train validated batches by hand; this queue automates
|
||||
# it with batching + automatic batch bisection (a red batch of N costs ~log2(N)
|
||||
# revalidations instead of N). Mergify Open Source plan: free, unlimited, public repo.
|
||||
#
|
||||
# GOVERNANCE (non-negotiable, mirrors CLAUDE.md Hard Rules #21/#22 + the owner's
|
||||
# pre-merge ⭐ gate):
|
||||
# • A PR enters the queue ONLY via the `queue` label — applied by the owner (or a
|
||||
# session acting for the owner) AFTER the pre-merge ⭐ report/decision. The label
|
||||
# IS the merge approval; Mergify only executes it.
|
||||
# • During a release-freeze (open issue labeled `release-freeze`), do NOT label PRs
|
||||
# targeting the frozen branch — the freeze is a human-honored coordination signal
|
||||
# the queue cannot see. Retarget to the active release/vX+1 first (Hard Rule #21).
|
||||
# • Never label a PR another session is actively working (Hard Rule #22b).
|
||||
# • Fallback path if Mergify misbehaves or the OSS plan changes: the manual
|
||||
# merge-train runbook (docs/ops/MERGE_TRAIN.md) — remove labels, proceed by hand.
|
||||
|
||||
queue_rules:
|
||||
- name: release
|
||||
# Any current or future release branch — the reason GitHub's native queue was
|
||||
# rejected (no wildcard support on personal-account repos).
|
||||
queue_conditions:
|
||||
- base~=^release/v\d+\.\d+\.\d+$
|
||||
- label=queue
|
||||
- -draft
|
||||
- -conflict
|
||||
# "Everything that ran is green, nothing still running, AND the always-on
|
||||
# anchor check succeeded" — robust to the path-filtered fast-gates (docs-only
|
||||
# PRs skip code jobs; matrix shard names vary) while never fail-open: a PR with
|
||||
# zero checks cannot vacuously merge, because `Merge integrity` runs on EVERY
|
||||
# non-draft PR (quality.yml) and must be an affirmative success. Review approval
|
||||
# is intentionally NOT a condition here: the owner-applied `queue` label IS the
|
||||
# approval in this repo's single-maintainer model (see governance header).
|
||||
merge_conditions:
|
||||
- "#check-failure=0"
|
||||
- "#check-pending=0"
|
||||
- "#check-success>=1"
|
||||
- check-success=Merge integrity (changelog + generated skills)
|
||||
# Batching: validate up to 10 queued PRs together (the manual train's sweet spot);
|
||||
# don't hold a lone PR hostage waiting for siblings.
|
||||
batch_size: 10
|
||||
batch_max_wait_time: 5 min
|
||||
# Squash keeps the one-commit-per-PR history the CHANGELOG reconciliation expects.
|
||||
merge_method: squash
|
||||
|
||||
pull_request_rules:
|
||||
- name: clean up the queue label after merge
|
||||
conditions:
|
||||
- merged
|
||||
actions:
|
||||
label:
|
||||
remove:
|
||||
- queue
|
||||
1
changelog.d/maintenance/mergify-queue.md
Normal file
1
changelog.d/maintenance/mergify-queue.md
Normal file
@@ -0,0 +1 @@
|
||||
- **Merge queue (D5)**: reviewed PRs now merge through the Mergify queue (`.mergify.yml`, Open Source plan) — entry is the owner-applied `queue` label AFTER the pre-merge ⭐ gate; batches of up to 10 validate together with automatic bisection of red batches (~log2(N) instead of N revalidations); the manual merge-train is codified as the fallback runbook in `docs/ops/MERGE_TRAIN.md` with the freeze/cross-session guardrails
|
||||
63
docs/ops/MERGE_TRAIN.md
Normal file
63
docs/ops/MERGE_TRAIN.md
Normal file
@@ -0,0 +1,63 @@
|
||||
---
|
||||
title: Merge Queue & Manual Merge-Train Runbook
|
||||
---
|
||||
|
||||
# Merge Queue & Manual Merge-Train Runbook
|
||||
|
||||
Since v3.8.49 (WS3.2/WS3.4 of the quality/velocity plan) the default merge path for
|
||||
reviewed PRs into `release/vX.Y.Z` is the **Mergify merge queue** (`.mergify.yml`);
|
||||
the **manual merge-train** documented below is the FALLBACK — used during incidents,
|
||||
release freezes, or if the Mergify Open Source plan ever changes.
|
||||
|
||||
## Default path: the Mergify queue
|
||||
|
||||
1. PR is reviewed/greened by the campaigns and approved by the owner's pre-merge ⭐
|
||||
gate (the report + per-item decision — see `/merge-prs` Step 0.75).
|
||||
2. The owner (or the session acting on the owner's decision) applies the **`queue`**
|
||||
label. The label IS the merge approval; Mergify only executes it.
|
||||
3. Mergify batches up to 10 queued PRs, validates the batch against the fast-gates,
|
||||
and merges (squash). A red batch is **bisected automatically** — the offending PR
|
||||
is isolated in ~log2(N) revalidations and unqueued; the rest proceed.
|
||||
4. Post-merge, the continuous release-green workflow validates the new tip on push
|
||||
and opens an attribution issue if the combination regressed (never auto-revert).
|
||||
|
||||
Guardrails (mirror `CLAUDE.md` Hard Rules #21/#22):
|
||||
|
||||
- **Release freeze open** → do NOT label PRs targeting the frozen branch; retarget to
|
||||
the active `release/vX+1` first.
|
||||
- **Another session's in-flight PR** → never label it; only the owning session queues
|
||||
its own work.
|
||||
- Tests-only diffs and `hotfix`-labeled PRs already run reduced CI (see
|
||||
`RELEASE_CHECKLIST.md` → Hotfix Fast-Lane); the queue conditions accept whatever
|
||||
check set actually ran (`#check-failure=0` + `#check-pending=0`).
|
||||
|
||||
## Fallback: the manual merge-train
|
||||
|
||||
Used when the queue is unavailable. This codifies the practice that drained 33 PRs in
|
||||
one day during the v3.8.47 cycle:
|
||||
|
||||
1. **Assemble the batch** (~10–30 reviewed+approved PRs). Check `linked:` collisions
|
||||
(same `tap.testFiles`, same CHANGELOG hunks) and serialize those.
|
||||
2. **Validate ONCE**: in an isolated worktree off the release tip, merge all batch
|
||||
heads locally, then run the release-equivalent suite
|
||||
(`npm run check:release-green`, add `--with-build` before a release).
|
||||
3. **Green** → merge the PRs in sequence (re-checking `state,headRefOid` before each —
|
||||
a PR whose head moved re-enters review). Prove the net diff of each merge is the
|
||||
PR's own change (no auto-resolve reverts: audit `git diff --stat` for
|
||||
out-of-scope deletions).
|
||||
4. **Red** → bisect the batch by halves (validate each half) instead of re-validating
|
||||
one-by-one; drop the offending PR back to the review queue with the evidence.
|
||||
5. **Never**: merge during a freeze into the frozen branch; `git stash` anywhere;
|
||||
blanket-rerun CI hoping a red goes away (rule: a red is information).
|
||||
|
||||
## Tiering (why the queue is safe with fast-gates only)
|
||||
|
||||
- **Per PR** (quality.yml fast-gates): TIA-impacted tests + full unit 4-shard +
|
||||
vitest + lint bag + typecheck + docs/changelog integrity.
|
||||
- **Per batch/tip** (continuous release-green): `--quick` HARD gates on every push to
|
||||
the release branch; full `--with-build --full-ci` sweeps 3×/day.
|
||||
- **Per release** (ci.yml on the release PR): the complete matrix incl. E2E ×9,
|
||||
package-artifact + tarball boot-smoke, coverage/ratchets.
|
||||
|
||||
Nothing is validated less than before — the heavy surface just runs per batch/tip
|
||||
instead of per PR, which is what removes the O(N) round-trips.
|
||||
Reference in New Issue
Block a user