Status: Active Owner: Platform Architecture Phase: 1.D ofDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
docs/recommendations/DEV_VELOCITY_AND_ARCHITECTURE_PLAN_2026-04-22.md
The unit-test suite is 1,657 test files / ~7,167 tests as of 2026-04-22, with a wall-clock cost of ~3 m 43 s unsharded (per reports/perf/baseline-2026-04-22.md). Vitest already runs files in parallel within a single process (pool: 'threads', maxWorkers: '50%' in CI — see vitest.config.ts), but a single CI runner still pays the full ~4-minute wall-clock.
Sharding splits the suite across N parallel CI runners, each running 1/N of the files. Combined with Vitest’s per-file in-process parallelism, this can bring CI test wall-clock down to ~1 minute at N=4 (verified locally; see “Measurement” below).
Quick reference
1/1 (no sharding) which is safe to use locally.
The wrapper writes a per-shard JUnit XML report at reports/test-shards/unit-${shard}-of-${total}.xml so each CI matrix job’s results can be uploaded as a separate artifact without clobbering siblings.
How Vitest sharding works
--shard=$INDEX/$TOTAL partitions the discovered test files (not individual tests) deterministically by hash. Equal TOTAL values across runs produce stable distributions, so a flake in shard 3 can be re-run as --shard=3/4 and pick up the same files.
Reference: https://vitest.dev/guide/cli.html#shard
Recommended GitHub Actions wiring (not yet applied to .github/workflows/build.yml)
npm run test:coverage step to a sharded matrix is not done in this PR — it’s a CI-workflow change that should land in its own PR after a project owner can validate against billing budgets (matrix runs scale CI minutes linearly; 4 shards × ~1 min ≈ 4 CI minutes total vs 1 × ~4 min ≈ 4 CI minutes, but with 4× the wall-clock parallelism).
Coverage caveat
Coverage thresholds invitest.config.ts (statements: 40, branches: 35, functions: 40, lines: 40) only make sense on the full suite, not per shard. If we wire sharding to the coverage step, we must also add a “merge coverage” job after the matrix that combines per-shard coverage/coverage-final.json files via nyc merge (or Vitest’s own merge tooling) before checking thresholds.
For Phase 1.D, the recommendation is:
- Use sharding for the fast-feedback unit-tests gate (
test:unit:shard). - Keep the coverage step single-runner (
test:coverage) until merge tooling is proven on this codebase.
Measurement on this branch
Captured on the Cursor Cloud VM (Linux, 4 vCPU / 16 GB RAM), filtering withSKIP_SUPABASE_TESTS=true CI=true:
| Shard | Files | Tests | Wall-clock | Notes |
|---|---|---|---|---|
1/100 (smoke) | 6 | 48 | 2.78 s | Confirms shard CLI works and JUnit emits correctly. |
2/4 | 136 | 1,681 | 61 s | One quartile of the suite. Includes 5 pre-existing skips. |
| baseline (no sharding) | 544 | 7,167 | 3 m 43 s | From reports/perf/baseline-2026-04-22.md. |
--total=4 (in parallel CI matrix): ~62 s — a ~3.6× speedup vs the unsharded baseline.