Repository navigation
Release branches have no CI and no branch protection, and no checks are required anywhere #54
Description
Summary
Branches other than the default branch have no ruleset coverage and no CI, and separately, no status checks are required on any branch. This was found while delivering #53, which targeted release/v1.0.0. Four problems compound: the first two are verification gaps, and the last two are breaches of requirements the MSXOrg ways-of-working canon already states — not local preferences to be debated.
1. No CI runs on pull requests against release branches
.github/workflows/Process-PSModule.yml only listens to pull_request events whose base branch is main:
on:
pull_request:
branches:
- mainA pull request based on release/** therefore gets no checks at all, and gh pr checks reports "no checks reported on the branch".
2. A green workflow_dispatch run is not equivalent to a green pull-request run
The workaround for problem 1 is dispatching the workflow manually against the branch. That is weaker than it looks, because some jobs are gated on the event type.
Verified on #53:
| Job | Dispatch run 30756441401 | Post-merge run 30757319554 |
|---|---|---|
Lint-Repository |
skipped | success |
Lint-Repository is the super-linter job that runs markdownlint, textlint and codespell. In a pull request that added three new markdown pages and reworked the README, the entire prose-linting surface silently did not run. The change happened to be clean — it was pre-checked locally against .github/linters/ and the post-merge run confirmed it — but nothing in the dispatch result said "prose was never linted".
Anyone using dispatch as a stand-in for pull-request CI needs to know which jobs it does not exercise. Ideally dispatch would not silently skip verification jobs at all.
3. Release branches have no branch protection whatsoever
This is the serious one. The repository has a single ruleset, GitHub Flow (id 19735208), whose condition is:
{ "ref_name": { "include": ["~DEFAULT_BRANCH"], "exclude": [] } }~DEFAULT_BRANCH resolves to main, so the ruleset does not apply to anything else. Confirmed directly against the API:
$ gh api /repos/PSModule/Yaml/rules/branches/main
deletion
required_linear_history
pull_request
non_fast_forward
$ gh api /repos/PSModule/Yaml/rules/branches/release%2Fv1.0.0
(empty — no rules apply)There is also no classic branch protection on either branch (/branches/*/protection returns 404 for both). So on release/**, all of the following are currently permitted:
- Pushing directly, with no pull request at all — the
pull_requestrule is what requires one, and it is scoped tomain. - Force-pushing —
non_fast_forwardis not enforced. - Deleting the branch —
deletionis not enforced. - Non-linear history, and any merge method, not just squash.
And for pull requests that do target a release branch, none of require_code_owner_review, required_review_thread_resolution, require_last_push_approval or dismiss_stale_reviews_on_push apply. #53 reported mergeStateStatus: CLEAN and was mergeable by anyone with write access, unreviewed, with zero checks.
A release branch is the branch a version actually ships from. It currently has strictly weaker protection than any feature branch merging into main.
This violates two canonical release-management requirements
The gap is not just a local misconfiguration — the release-management capability spec states requirements that this configuration cannot satisfy:
A release per merge. One merged PR to a release branch is one release, and the PR review gate is the release gate.
There is no PR review gate on release branches here, so the release gate the spec relies on does not exist.
Only artifact-affecting changes release. A change that does not flow into the artifact (documentation, CI config) MUST NOT produce a release — though validation still runs on every merge.
Validation does not run on release-branch pull requests at all, and the matching success criterion — "a documentation-only merge produces no new version but still runs its CI checks" — is not met. #53 was exactly that case: a documentation-only merge into a release branch, with no CI.
So problems 1 and 3 are two halves of one documented requirement that the repository configuration does not currently meet.
4. No status checks are required anywhere, so auto-merge does not wait for CI
The ruleset contains no required_status_checks rule at all — not for release branches, and not for main either. The gate on main is code-owner review (CODEOWNERS assigns * @PSModule/module-maintainers), with a reviewer expected to notice red checks.
The consequence is easy to miss: GitHub's auto-merge only waits for checks it has been told are required. With no required status checks configured, an armed auto-merge fires as soon as the review conditions are satisfied, regardless of whether CI has finished or passed. "Auto-merge is armed" reads as "this will wait for CI"; on this repository it does not.
The review rules do provide real cover — require_last_push_approval and dismiss_stale_reviews_on_push mean a later push drops the approval rather than slipping through it — so this is not currently being exploited. #47 is armed as of writing with all 66 checks complete and green on 6ec4321, which is safe. But the safety comes from the timing of the approval, not from any rule that says CI must pass.
This is a conformance gap, not an open decision
Requiring status checks has already been decided. Branching and Merging is normative on the point:
A branch ruleset on the protected branch defines the merge requirements every pull request must satisfy before it can land — the required status checks, the required approvals, and any others the ruleset enforces ... The ruleset is configured on the repository (in its settings), not in these files; this section defines what it must enforce.
It then describes auto-merge as squash-merging "the moment every one of those requirements is satisfied — and not before". With no required status checks declared, that "and not before" guarantee does not hold, because there is nothing for auto-merge to wait on beyond approval.
So this repository is in breach of the branching canon, and problem 3 is a second breach of the same document's protected-branch model. The question is not whether CI should be binding — canon already says it must be. The only genuinely open part is operational: which check contexts to name.
This makes required status checks the higher-value half of the fix rather than a footnote to the trigger change. Fixing problem 1 alone makes checks visible on release-branch pull requests; it does not make them binding anywhere.
Proposed changes
Four independent fixes. Items 3 and 4 are the ones that matter most, and both are conformance repairs rather than new policy: 3 closes the governance hole, and 4 is what makes CI actually binding rather than merely visible.
-
Extend the workflow trigger so release branches get pull-request CI:
on: pull_request: branches: - main - 'release/**'
Confirm against
PSModule/Process-PSModulethat the reusable workflow keepsPublish-SiteandPublish-Moduleskipped for non-mainbases. They were correctly skipped in run 30756441401, so this looks safe, but it should be verified rather than inferred from one run. If the guard is not upstream, that part belongs inPSModule/Process-PSModuleinstead. -
Make
workflow_dispatchruns honest. Either stop gating verification jobs such asLint-Repositoryon the event type, or have the workflow summary state plainly which jobs were skipped because the run was not a pull request. Silent skipping is what makes dispatch misleading as a substitute. -
Extend ruleset coverage to release branches. Add
refs/heads/release/**to theGitHub Flowruleset'sref_name.include, so release branches inherit the pull-request requirement, code-owner review, thread resolution, squash-only merges, linear history, and force-push and deletion protection. -
Add a
required_status_checksrule covering bothmainandrelease/**, so CI is binding rather than advisory and auto-merge genuinely waits for it. This is not an open design question — Branching and Merging already requires the ruleset to enforce required status checks, so adding the rule brings the repository back into conformance rather than introducing a new policy. The open part is purely operational: which check contexts to name, given that the reusable workflow's job names can change betweenProcess-PSModuleversions. Prefer contexts that are stable across upgrades over pinning every matrix leg.
This is likely an organisation-wide pattern rather than a PSModule/Yaml quirk — any PSModule repository that uses a release branch has the same exposure, and the missing required-checks rule affects every repository using this ruleset regardless of whether it has a release branch. If the ruleset is templated from PSModule/.github, the fix belongs there and this issue should route accordingly.
Acceptance criteria
- A pull request based on a
release/**branch reports the same checks as one based onmain. Publish-SiteandPublish-Moduleremain skipped for non-mainbases.- Release branches require a pull request, code-owner review, and resolved review threads, and reject force-pushes and deletion.
- The release-management spec's "the PR review gate is the release gate" and "validation still runs on every merge" hold for release branches in practice, not just on paper.
- A
required_status_checksrule exists for bothmainandrelease/**, satisfying Branching and Merging, and an armed auto-merge does not land a change whose checks have not finished. - A
workflow_dispatchrun either exercises the same verification jobs as a pull-request run, or reports which ones it skipped. - No behaviour change for pull requests targeting
main.
Out of scope
- The release process itself.
- Any content change in 🌟 [Major]: New PowerShell module v1.0.0 with complete YAML 1.2.2 command suite #47 or 📖 [Docs]: YAML commands grouped by task with in-depth guides for each area #53.
Activity
MariusStorhaug commentedon Aug 2, 2026
Adding evidence from stacking #53 on
release/v1.0.0, because the problem is larger than the missing checks and that changes how this should be prioritised.The gate is not merely unsatisfiable — it is absent
The ruleset is scoped to
mainonly:The
pull_requestrule onmaincarriesrequire_code_owner_review: true,required_review_thread_resolution: true, andrequire_last_push_approval: true. None of that applies to arelease/**base.The observable consequence: #53 reported
mergeStateStatus: CLEAN, notBLOCKED. A release-stacked pull request therefore has no required checks, no required review, and no required thread resolution — it can be merged unreviewed by anyone with write access.release/**also has nodeletionornon_fast_forwardprotection.That makes this a governance gap rather than a CI-convenience gap, and the current title understates it.
workflow_dispatchis not an equivalent substituteThe issue notes that manual dispatch runs without pull-request context. Concretely, on run 30756441401 (dispatched against
group-functions-and-docs)Lint-Repositorywas skipped, so super-linter never ran — meaning markdownlint, textlint and codespell never saw that pull request's three new documentation pages or its rewrittenREADME.md. 53 jobs reported success while the repository-wide lint gate had silently not executed.Those files were linted locally before the merge and then genuinely verified by run 30757319554 once the content reached a real
pull_requestrun on #47. But anyone reading "dispatch run is green" as equivalent to "PR run is green" would have shipped unlinted content.Suggested amendments
release/**base enforces the same review and thread-resolution requirements asmain, which is a ruleset change (extend the existingGitHub Flowruleset's target patterns) and not something the workflow trigger alone can fix.Lint-Repositoryis one of the jobs that does not run underworkflow_dispatch, so dispatch cannot be used as a stand-in for the missing checks.The two-part fix matters: extending only the
pull_requesttrigger would give release-stacked pull requests checks while still leaving them mergeable without review.[-]Stacked pull requests against release branches run no CI checks[/-][+]Release branches have no CI and no branch protection[/+][-]Release branches have no CI and no branch protection[/-][+]Release branches have no CI and no branch protection, and no checks are required anywhere[/+]🌟 [Major]: New PowerShell module v1.0.0 with complete YAML 1.2.2 comm…
📖 [Docs]: Review readiness rejects absent CI and undeclared merge che…