Skip to content

chore(ci): add a validate workflow so the published CLI has a gate (W37-1545) - #31

Merged
sonpiaz merged 2 commits into
mainfrom
chore/w37-1545-ci
Sep 21, 2026
Merged

sonpiaz merged 2 commits into
mainfrom
chore/w37-1545-ci

Conversation

@sonpiaz

@sonpiaz sonpiaz commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

What

One validate workflow for this repo: npm ci → build → lint → unit tests, on every pull request and every push to main.

Why

Affitor/cli is public and publishes affitor to npm, and it had no CI at all — no .github/ directory on main, gh pr checks 30 reports no checks, and PR #29 merged without a single check running. Every gate was a person remembering to run three commands by hand. That was measured on 2026-09-20 while reviewing PR #30, and it is why this ticket exists.

Concretely, the 9 exit-code cases packages/cli/tests/exit-codes.test.ts added in #29 went in with nothing watching them. After this, an agent-facing onboard/whoami exit-code regression goes red.

Measured before writing it (origin/main e431706)

So the gate starts green on arrival rather than red — a CI job that fails the moment it lands is worse than no CI, because it blocks the open PRs instead of protecting them.

Step Result
npm run build --workspaces clean (tsc × 3)
npm run lint --workspaces clean (tsc --noEmit × 3), exit 0
npm run test --workspaces 132/132 pass — recipes 19, cli 104, mcp 9, 0 failures
npm ci --dry-run resolves, so package-lock.json is in sync with the three workspaces

An independent reviewer re-ran all three on the base and got the same numbers. The workflow also already proved itself: validate ran green on this PR's own head in 27s, because pull_request takes the workflow from the PR.

Hardening (second commit, after review)

  • Both actions pinned to a commit, not the v4 tag — a tag can be repointed, and this repo publishes to npm. SHAs resolved against the GitHub API, not copied from the review.
  • persist-credentials: false — the job runs code from the pull request; the token should not sit in .git/config for that code to read.
  • No --if-present — all three workspaces declare all three scripts today, so a missing script means a package quietly stopped being checked. Re-measured without the flag: still 132/132.
  • timeout-minutes: 15 and concurrency with cancel-in-progress.
  • permissions: contents: read.

Deliberately left out, written down rather than hidden

  • No Node version matrix. packages/cli declares engines.node >= 18, so a break that only shows on the oldest supported runtime still gets through. vitest@3.2.6 does support Node 18, so the matrix is plausible — but it could not be measured here, and an unverified matrix risks the red-on-arrival problem above. Follow-up, same ticket.
  • validate is not a required check. Measured: branches/main/protection → 404 not protected, rulesets → []. A check cannot be required before it has ever run on main, so this is a step for whoever merges, not a change to this file. Until then the workflow is advisory.
  • Also noted and not done: npm audit, a publish dry-run / --version smoke test.

Scope

Adds one file. Touches no source, no tests, no package manifest, no publish path. Nothing here can change what the CLI does for a user.

Note on the other open PRs

A workflow landing on main does not retroactively appear on PRs #30, #24 and #1 — they each need a new pull_request event (a push or a reopen) before validate runs on them.

🤖 Generated with Claude Code

sonpiaz and others added 2 commits September 21, 2026 02:14
…37-1545)

`Affitor/cli` is public and publishes `affitor` to npm, and it had no CI at all:
no `.github/` on main, `gh pr checks` reported none, and PR #29 merged without a
single check. Every gate was a person remembering to run three commands locally.

One `validate` job on pull_request and pushes to main, mirroring the CMS repo:
npm ci, then build, lint (`tsc --noEmit` per workspace) and the vitest suites
across all three workspaces.

Measured on origin/main e431706 (2026-09-21 02:2x PT) before writing this, so the
gate starts green rather than red on arrival: build clean, lint clean,
132/132 tests pass (recipes 19, cli 104, mcp 9). `npm ci --dry-run` resolves, so
package-lock.json is in sync with the workspaces.

Known debt, deliberately not in this first pass: `packages/cli` declares
engines.node >= 18 but the job only runs Node 20, so a break that only shows on
the oldest supported runtime still gets through. A matrix is the fix; it is left
out here because it could not be measured on this machine and a gate that goes
red on arrival is worse than none.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-1545)

Round 1 review was ĐẠT with 0 P1. Four of its findings were cheap and in-file,
and they matter more here than in a private repo because this one publishes to
npm from a public repository.

- Pin both actions to a commit instead of the `v4` tag. A tag can be repointed
  at any time. SHAs resolved independently against the GitHub API rather than
  copied from the review: actions/checkout v4 -> 11d5960, setup-node v4 -> 49933ea.
- `persist-credentials: false`. The job runs code from the pull request, so the
  token should not be sitting in .git/config where that code can read it.
- Drop `--if-present`. All three workspaces declare build, lint and test today,
  so a missing script means a package quietly stopped being checked; a gate
  should fail loudly instead. Re-measured without the flag: 132/132 still pass
  (recipes 19, cli 104, mcp 9), build and lint clean.
- `timeout-minutes: 15` and `concurrency` with cancel-in-progress, so a hung job
  cannot occupy a runner and superseded pushes stop burning minutes.

Not taken here, on purpose: making `validate` a required check. Measured
`gh api repos/Affitor/cli/branches/main/protection` -> 404 not protected and
`rulesets` -> []. A check cannot be required before it has ever run on main, so
that is a step for whoever merges this, not a change to this file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonpiaz
sonpiaz merged commit 435da6f into main Sep 21, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant