From 65770a37963b84215a834b6ce7181e25b2459f44 Mon Sep 17 00:00:00 2001 From: Gabor Szabo Date: Thu, 14 May 2026 05:40:37 +0200 Subject: [PATCH] chore(ci): document main branch protection at release boundary (#108) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirrors `dev`'s four required status checks onto `main` (Lint & Format, Type Check, Test, Migration Check; strict=true). Documents the new protection in three places so future contributors and the release-trigger runbook stay accurate: - `docs/_base/PIPELINE_CONTRACT.md` — Merge Conditions table now shows the four `main` gates explicitly; verification-date refreshed to 2026-05-14; enforce_admins note expanded to call out that the empty-`feat:` trigger PR must now wait for the same four checks before admin-merge. - `docs/GIT-GITHUB-GUIDE.md` — branch summary + release-flow step 2 reflect the enforced gates. - `docs/_base/RUNBOOKS.md` — release-please recovery procedure step 4 now spells out the new wait-for-CI requirement explicitly. `enforce_admins: false` preserved per #108 out-of-scope, so the release-trigger admin-merge workaround still works (it just has to wait for CI like every other PR to `main`). The protection itself is applied out-of-band via `gh api -X PUT repos/w7-mgfcode/ForecastLabAI/branches/main/protection` because branch-protection writes are not reviewable in a PR diff; this commit documents the post-write state. Closes #108. --- docs/GIT-GITHUB-GUIDE.md | 6 +++--- docs/_base/PIPELINE_CONTRACT.md | 6 +++--- docs/_base/RUNBOOKS.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/GIT-GITHUB-GUIDE.md b/docs/GIT-GITHUB-GUIDE.md index da2afd38..d3196ec2 100644 --- a/docs/GIT-GITHUB-GUIDE.md +++ b/docs/GIT-GITHUB-GUIDE.md @@ -25,8 +25,8 @@ flowchart LR | Branch Type | Purpose | Protection | Lifecycle | | --- | --- | --- | --- | | `feat/*` | Feature work | No strict protection | Deleted after merge | -| `dev` | Integration | CI checks required | Long-lived | -| `main` | Release | Strict CI + release flow | Long-lived | +| `dev` | Integration | CI checks required (4 gates: Lint & Format, Type Check, Test, Migration Check) | Long-lived | +| `main` | Release | Same 4 CI gates + release flow | Long-lived | | `phase-*` | Audit snapshot | Protected, immutable | Permanent | --- @@ -118,7 +118,7 @@ sequenceDiagram ### 4.2 Release Flow 1. Create PR from `dev` → `main` when integration is stable. -2. CI must pass on the PR. +2. CI must pass on the PR — the four `main` gates (Lint & Format, Type Check, Test, Migration Check) are enforced at the branch-protection layer, so the merge button stays disabled until they go green. 3. Merge to `main` triggers release-please. 4. If a release is created, artifacts are built and attached to the GitHub Release. diff --git a/docs/_base/PIPELINE_CONTRACT.md b/docs/_base/PIPELINE_CONTRACT.md index 567888ce..e4c6b39c 100644 --- a/docs/_base/PIPELINE_CONTRACT.md +++ b/docs/_base/PIPELINE_CONTRACT.md @@ -37,15 +37,15 @@ A "release commit" only occurs when a maintainer merges the open Release PR — ## Merge Conditions (ALL must be true) -Branch protection (verified via `gh api repos/w7-mgfcode/ForecastLabAI/branches/{dev,main}/protection` on 2026-05-12): +Branch protection (verified via `gh api repos/w7-mgfcode/ForecastLabAI/branches/{dev,main}/protection` on 2026-05-14): - [ ] **`dev`** — required status checks (strict, must be up-to-date): `Lint & Format`, `Type Check`, `Test`, `Migration Check`; `required_approving_review_count: 1`; `dismiss_stale_reviews: true`; `allow_force_pushes: false`; `allow_deletions: false`. -- [ ] **`main`** — `required_approving_review_count: 1`; `allow_force_pushes: false`; `allow_deletions: false`; no required status checks at the branch-protection layer (release-please-managed; `cd-release.yml` runs after merge). +- [ ] **`main`** — required status checks (strict, must be up-to-date): `Lint & Format`, `Type Check`, `Test`, `Migration Check`; `required_approving_review_count: 1`; `dismiss_stale_reviews: false`; `allow_force_pushes: false`; `allow_deletions: false`. Mirrors the four `dev` gates so the release boundary (`dev` → `main`) cannot land with broken CI (issue #108). - [ ] Conventional Commit message validated by `.claude/hooks/check-commit-format.sh` locally. - [ ] No unresolved review comments. - [ ] Branch up-to-date with `dev` (for `dev` merges) or `main` (for `dev → main` PRs). -> Note: `enforce_admins: false` on both branches — admin merge is possible (see "release-please skipped the bump after a dev → main merge" runbook), but should be reserved for the empty-`feat:`-trigger workaround. +> Note: `enforce_admins: false` on both branches — admin merge is possible (see "release-please skipped the bump after a dev → main merge" runbook), but should be reserved for the empty-`feat:`-trigger workaround. **With the `main` status-checks added (#108), an admin-merge of the empty-`feat:` trigger still has to wait for the same four CI jobs to complete on the trigger PR before merging — plan for ~3-5 min wall-clock between push and merge.** ## Failure Gates diff --git a/docs/_base/RUNBOOKS.md b/docs/_base/RUNBOOKS.md index c9fb743f..3f6919eb 100644 --- a/docs/_base/RUNBOOKS.md +++ b/docs/_base/RUNBOOKS.md @@ -76,7 +76,7 @@ gh run view --log | grep -E "(Considering|No user facing)" 1. Open an issue tracking the release (`release: cut vX.Y.Z for ...`). 2. Branch off `dev`: `git switch -c feat/release-trigger-X-Y-Z`. 3. `git commit --allow-empty -m "feat(release): trigger vX.Y.Z release for (#)"`. -4. PR to `main`, CI green, admin-merge — the empty `feat:` becomes the merge subject and release-please bumps PATCH (pre-1.0 config). Reference example: PRs #99 → #100 → #101 for v0.2.8. +4. PR to `main`, **wait for all four `main` status checks to go green** (Lint & Format, Type Check, Test, Migration Check — enforced at the branch-protection layer since #108), then admin-merge — the empty `feat:` becomes the merge subject and release-please bumps PATCH (pre-1.0 config). Reference example: PRs #99 → #100 → #101 for v0.2.8. Plan ~3-5 min between push and the merge button becoming available. ## Break-Glass Procedures