adding-ci-gates
Use when adding new CI checks or gates to a repository — batching several gate tickets onto one branch, deciding whether a gate ships now or is deferred, re-checking a gate design against the live mai
SKILL.mdplugins/react-frontend-sdlc/skills/adding-ci-gates/SKILL.md
GitHubAdding CI Gates
Profile keys consumed
ci.providerci.workflowsci.required_checksmake.lintmake.formatframework.package_manager
Overview
A batch of new CI gates lands cleanly only when each gate is independent, is designed against the
live main branch rather than the ticket that requested it, and carries its own coverage. The
failure mode is a batch where two gates edit the same workflow, or where a gate was specified
against a make target that has since been split or renamed.
When to use
- Several CI-gap tickets are being implemented onto one branch.
- A new workflow, a new CI gate script, or a new lint target is being added.
- A gate needs new infrastructure — a new image, cloud credentials, a new external tool.
- Bot reviewers (CodeRabbit, cubic) have commented on a workflow or Makefile change.
- Not for: diagnosing a gate that is already red — that is the ci-infrastructure-failure-diagnosis skill, and for a refactor that only moves an existing gate between execution contexts, use the ci-infrastructure-refactoring skill.
Applicability by repository shape
- React SPA shape (feature modules under the source root, a bootable app, an aggregate CI
target): yes — workflows in the paths listed by
ci.workflows, gate scripts in the CI scripts directory, validated by dedicated workflow-syntax, workflow-security, and compose-validation lint targets that ride the aggregate mapped bymake.lint. - Next.js app shape (routed pages, no aggregate duplication gate): partial — same workflow and CI-script layout, but the only workflow-lint target is a workflow-security one; nothing lints workflow syntax or the compose files.
- Component-library shape (Storybook-first, no bootable app, published package): partial — same workflow and Bats-suite layout, but no workflow-lint make target, so workflow-syntax errors surface only on the runner.
Procedure
One gate, one ticket, one commit. Split the batch so no two gates edit the same file. If two gates must touch the same workflow, merge them into a single ticket instead of interleaving commits. Isolation is what makes a bad gate revertable without unpicking the others.
Re-verify against the live branch, not the ticket. Read the current file before designing:
git fetch origin main git show origin/main:Makefile | grep -n '^test-unit' git show origin/main:.github/workflows/static-testing.ymlTargets get split (a single test target becoming dev-side and prod-side phases), thresholds get tuned, and workflows get refactored between the ticket being filed and being worked. Read the workflows named by
ci.workflows, the Makefile, and the CI scripts directory for a gate that already covers the space before adding a second one.Assess burn-down risk before committing to the batch. A gate built on an existing pattern (one more target in the aggregate mapped by
make.lint, one more Bats file) is low risk. A gate that needs a new Docker image, new cloud credentials, or a new threshold to be calibrated is high risk — land the cheap gates first and re-file the rest, rather than holding the batch open.Give the gate its own coverage. A new make target needs a row in the repository's make-target coverage manifest and a Bats case that drives it; a new gate script needs a must-fail fixture proving the gate really fires. A gate with no failing fixture can pass vacuously forever.
Apply the workflow hygiene the security lint already enforces: actions pinned to a commit SHA, top-level
permissions: {}with the minimum scope granted per job,persist-credentials: falseon checkout,concurrencywithcancel-in-progress: trueon pull-request workflows andfalseon deploy and release workflows, and a same-repo guard on any job that reaches a privileged account.Triage bot findings, do not batch-apply them. Apply findings about permissions, race conditions, and token scoping. Reject findings that assume a toolchain the repository does not use — always check the installer declared by
framework.package_managerbefore accepting a finding that names a different one — and record the reason on the thread so it stands as evidence. Resolve each thread as its change lands.
Verification
- Every new gate is green, and every pre-existing gate is still green on the same run.
- The workflow-lint target passes locally where the repository shape has one.
- The aggregate mapped by
make.lintpasses after the formatter mapped bymake.format; skip either with a recorded note when it maps tonull. - A gate that is intended to become blocking is added to
ci.required_checksonly after it has been green on a full run. - Reverting a single gate's commit leaves the rest of the batch buildable.
Common mistakes
- Designing from the ticket text — re-read the file on
mainfirst; snapshots go stale fast. - Two gates editing one workflow in one batch — re-split, or merge them into one ticket.
- Adding a make target with no coverage row — the Bats target-coverage contract fails the build.
- Landing a high-risk gate to "see what happens" — it burns runner time on every unrelated pull request until it is fixed.
- Making a new gate green by relaxing an existing threshold or narrowing another gate's scope — fix the cause the gate reports instead.
- Writing a gate a bot-authored commit cannot satisfy — a commit-message gate needs a bot-guarded
relaxed config beside the strict human contract, keyed on an identity only the forge (
ci.provider) can write.