Status: partly live.
.github/workflows/ci.yml runs the Quality Gate job (toolchain from mise,
actions pinned by SHA, contents: read), release.yml runs the release job and linear-sync.yml
reconciles Linear. Not built: a workflow linter, a pin test, changeset status in the gate, and any
deploy (the Deploy Staging job is a no-op until the deploy questions DP1–DP7 are decided). The
code host is GitHub (ADR-0012).The model
- One required check, named
Quality Gate, runspnpm verify(0119). Branch protection onmainrequires it and nothing else. - Logic lives in pnpm scripts, not in workflow YAML. The workflow installs the toolchain and calls a script. A step that exists only in YAML cannot be reproduced locally, and moving to another CI host stays cheap.
- Local and remote run the same command. If
pnpm verifyis green on a clean clone, the check is green. The exceptions are listed under What green does not prove. - Verify needs zero secrets. A pull request from a fork has no vault access, and a verify stage that needs one cannot check a fork’s work at all.
What pnpm verify runs
pnpm verify:affected runs the turbo part for members changed since main only. Use it while iterating; the required check runs the full pnpm verify.
Checks CI adds beyond pnpm verify:
Run it locally
pnpm turbo run test --filter=<package-name>, pnpm validate, pnpm knip. The workflow’s job log prints the command it ran; copy that line.
Nothing in pnpm verify reads a vault, a .env or a token. If a step seems to need a credential, that is a bug in the step (see Secrets).
Rules for the workflow file
1
Toolchain from mise.toml
One setup step installs what
mise.toml pins, asserts that the pnpm pin equals packageManager
in package.json, caches the pnpm store and runs pnpm install --frozen-lockfile. It installs
tools and decides nothing.2
Pin every action by SHA
Each
uses: carries a full commit SHA and a semver comment. Renovate
keeps them current. Add a workflow lint (zizmor or equivalent) to catch unpinned actions and
injection patterns.3
Least privilege
Top-level
permissions are empty or contents: read. A job asks for more only when it must,
and id-token: write only on a job that logs in to the vault.4
No secrets in verify
The
verify job has no vault identity and no stored secret. Only deploy and release jobs may
log in, through OIDC (Secrets).5
Scope with affected, never skip
A pull request may use
--affected for turbo steps. main and release tags run everything.
pnpm validate, pnpm boundaries and pnpm knip never scope: they check repository-wide
facts.A check that cannot run is a failure
A step that is skipped because its tool is missing, its secret is absent or its input is empty must fail in CI, never pass. A local run may report a skip, with the reason; the CI run may not. Do not resolve a red gate by weakening it. Fix the thing the failure names, or change the gate through its own record (an ADR or the standard that created it), never in the same commit as the code that was failing it.What green does not prove
- No service is started.
pnpm verifybuilds and tests; it does not run a deployed system. - The runner image is only proven for the jobs that use it. A tool present on your machine and absent in CI fails in CI only. Keep tools in
mise.toml. - The vault and deploy paths are unexercised by verify. The first real deploy is the first time that code runs.
verify shows the repository conforms to its checks; it does not show the change is correct.
When CI is down
Use this only when the host cannot run workflows at all (billing lock, outage, startup failure). It is a break-glass path for gating, not a way to skip the gate.1
Gate the exact commit locally
From a clean worktree of the commit, never a checkout with local edits:
git fetch origin && git worktree add ../gate-<sha7> <sha>, then cd into it and run pnpm install --frozen-lockfile && pnpm verify && pnpm secrets:scan. Record the full SHA and the result. Do not ship a commit whose gate you did not see pass.2
Ship it by hand, as the owner
Follow Deploys: the owner runs the deploy command for that commit, and a production deploy needs the owner’s explicit approval. Never use
--no-verify or skip a step to save time.3
Smoke test and record
Run the deploy’s smoke test. Append a row to the table below in the same pull request or a docs follow-up: date, environment, full SHA, who deployed, gate result, smoke result, reason.
4
Reconcile
When CI is back, push one normal commit to
main so the pipeline’s view matches what is running.Enforcement status
See also Definition of done, Release and Testing.