check · git:20261020.ec0bed5 · 2026-10-20 · sha256 a3f5f37cce40d28f
check git:20261020.ec0bed5A
Immutable. This exact content never changes and is served at /api/v1/blob/a3f5f37cce40d28f.
---
name: check
description: Run local quality checks (typecheck, lint, build, tests). Quick check during development.
---
# Local Quality Check
Run all local quality checks. Use during development to verify the current
state quickly.
## First: self-review on four axes
Walk these BEFORE the commands below and before committing. A green suite says
the tests pass, not that the work is *good*, and none of these four is
something a runner reports.
1. **Implementation gaps** — the parallel change forgotten in a sibling command;
a test or a doc not added.
2. **Oddities** — dead code, leftover names, a half-applied refactor.
3. **Polish opportunities** — small in-scope improvements; **default to
including them** when they touch the same files and carry no
behavior-break risk.
4. **Regression risk** — the full suite, and the call sites of anything renamed
or removed.
Say out loud what you found, then fix it before running the checks.
## Steps
Run these sequentially and report results.
0. **Worktree pre-flight**: `[ -d node_modules ] || vp install --frozen-lockfile`.
`git worktree add` does not copy `node_modules`, and without it `vp check`
fails with an unnamed `typescript(tsconfig-error): Invalid tsconfig — Cannot
find type definition file for 'node'`, reading like a broken fixture
tsconfig.
1. `vp check --fix` (typecheck + lint + Prettier, auto-fix), then `vp run check`
— the exact command CI's `check-build-test` job runs. They are NOT equivalent:
`vp check --fix` has passed with 0 errors on a tree `vp run check` failed. Do
not substitute `vp run lint:fix`, which does not touch Prettier, so a
`lint:fix`-only run passes locally while CI fails `Formatting issues found`.
Run both; CI parity comes from the second.
2. `vp run typecheck:test` — type-checks `tsconfig.test.json` (`tests/**`).
`vp check` only type-checks `tsconfig.json` (src + types), which excludes
`**/*.test.ts`, and `vp test`'s `Type Errors` line covers only `*.test-d.ts`.
A wrong `import type` or stale mock shape in a test file is invisible without
this step.
3. `vp run build`.
Then regenerate the generated artifacts, unconditionally:
`vp run gen:all-matrices && vp run audit:coverage:check && vp run format`.
The suite carries a byte-for-byte guard per generated matrix, and the trigger
set is wider than any condition you would write — renaming a private provider
method stales `handled-property-wiring.json`, and a `verify.sh` edit with no
src change stales `cli-flag-coverage`.
4. `vp test run` — the whole unit suite. Prefer this over `vp run test`: nothing
sits between the caller and the verdict.
Read the summary's NUMBERS, not its colour, and read the `Errors` line, which
is NOT `Type Errors`. `Test Files N passed (N)` is self-consistent over a
suite that LOST files before they ran, so it cannot report its own shortfall:
a loaded host produces `[vitest-pool]: Failed to start forks worker` beside an
otherwise green summary. `vp test run --maxWorkers=4` is the remedy for the
whole `[vitest-pool]` / `[vitest-pool-runner]` family.
Also check WHICH PROJECT the summary belongs to — the summary line cannot
tell you, and a run launched from this worktree has been observed printing a
sibling project's suite. Assert the root in the same command that produces the
verdict, and read the suite's own rc, not the trailing grep's:
```bash
# Subshell so the `exit`s are safe to paste into an interactive shell.
(
log=$(mktemp) # NOT a fixed path: concurrent lanes share /tmp.
echo "log: $log" # print BEFORE the exits, or a failing run is unrecoverable.
vp test run > "$log" 2>&1; rc=$?
runs=$(grep -c 'RUN v' "$log")
[ "$runs" = 1 ] || { echo "expected 1 RUN header, found $runs -- attests to nothing; log: $log"; exit 1; }
run_root=$(grep -m1 -oE "RUN v[0-9.]+ .*" "$log" | sed 's/^RUN v[0-9.]* //')
[ "$run_root" = "$(pwd -P)" ] || { echo "WRONG PROJECT ($run_root) -- attests to nothing; log: $log"; exit 1; }
# The alternatives are chosen against the COLOURED bytes: vitest pads the
# label inside the dim escape, so ` Tests ` survives colouring and
# `Tests +[0-9]` does not. Do not tighten either one.
grep -E "Test Files| Tests |Type Errors|Errors.*[0-9]+ error" "$log"
if [ "$rc" != 0 ]; then
echo "SUITE FAILED rc=$rc; log: $log"
grep -qE '\[vitest-pool(-runner)?\]: ' "$log" \
&& echo " the pool lost workers before their files ran, so the passing counts above cover only what survived -- re-run with --maxWorkers=4"
exit 1
fi
# A run that exited 0 can still have COLLECTED fewer files than the tree
# holds (a stray filter, a narrowed include). Unanchored `(N)`: the
# coloured summary ends in an escape, not in `)`.
collected=$(grep 'Test Files' "$log" | grep -oE '\([0-9]+\)' | tail -1 | tr -d '()')
# `:(glob)` on every pathspec: git's bare `**` demands an intervening `/`
# while vitest's does not.
ondisk=$(git ls-files ':(glob)tests/**/*.test.ts' ':(glob)src/**/*.test.ts' \
':(glob)tests/**/*.test-d.ts' ':(glob)src/**/*.test-d.ts' | wc -l | tr -d ' ')
# `-ge`, not `=`: an untracked new test file is collected but not listed.
[ "${collected:-0}" -ge "$ondisk" ] || { echo "COLLECTED ${collected:-none} of $ondisk tracked test files over a run that exited 0 -- attests to nothing; log: $log"; exit 1; }
)
```
The wrong-project symptom is contention-dependent, not sticky — re-running
usually lands right.
## Output
Report as a table:
| Check | Result |
|-------|--------|
| typecheck + lint + format (`vp check --fix`) | pass/fail |
| test-project typecheck (`vp run typecheck:test`) | pass/fail |
| build | pass/fail |
| tests (N files, M tests) (`vp test run`) | pass/fail |
If all pass, confirm "All checks passed." If any fail, show the error output and
STOP — fix the failures and re-run before committing.
These checks attest to the working-tree state at the time of the run, so re-run
after any further edit.