diff --git a/AGENTS.md b/AGENTS.md index ba30f94f3a..db20d3f7e4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -176,6 +176,16 @@ pnpm run demo:acp # run examples/acp-agent โ€” the coding agent as an ACP # drive it from Zed or another ACP client) ``` +### Run the CI gates locally BEFORE marking a PR ready + +CI is the backstop, not the first place a gate runs. Before you open a non-draft PR or move one from draft to ready, run the same gates CI runs, on your own tree, and confirm they pass โ€” do not lean on CI (or a Codex pass) to discover a red gate you could have caught locally. The CI-equivalent local run is: + +```sh +pnpm run typecheck && pnpm run lint && pnpm run test:coverage && pnpm run test:snapshot && pnpm run doc-sync && pnpm run hygiene && pnpm run build +``` + +**`pnpm run test:coverage`, NOT `pnpm run test`, is the gating test command.** `pnpm run test` runs `vitest run` with no coverage; CI's node job runs `test:coverage`, which enforces a **per-file 100%** threshold on `packages/*/*/src`. A suite that is green under `test` can still fail CI on an uncovered line โ€” and that uncovered line is often *dead code* the 100% gate is correctly flagging for deletion (see [ยง Defensive patterns](#defensive-patterns-hard-won) "Line coverage is not behavior coverage"), not a missing test to bolt on. `hygiene` (knip + publint + workspace constraints + NodeNext types) and `test:snapshot` (keyless ACP replay) are likewise CI gates that `test` alone does not cover. When you rely on a Codex convergence pass for sign-off, check WHICH commands it ran: a pass that ran `test` but not `test:coverage`/`hygiene`/`doc-sync` has not exercised those gates. + ## Secrets / .env Real-API e2e tests (`pnpm run test:e2e`) read `DEEPSEEK_API_KEY` (and optionally `DEEPSEEK_BASE_URL`) from the environment, or from a gitignored `.env` at the repo root loaded via Node's native `process.loadEnvFile()`: