Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
## Context
The `testing` capability spec (Requirement: "Central runner subpath") already mandates that `@suaveplan/testing/runner` is the single, runner-swappable entry point for `describe`, `it`, `expect`, `vi`, and friends. 107 of 131 packages follow this. 19 do not — they import directly from `vitest`. Two more (`dev/testing`, `dev/testing-dom`) import from `bun:test`, but those are the wrapper-author packages and stay exempt.
Audit at `2026-05-03 ~14:00` confirmed the violation surface is **exactly four names** across all 19 packages: `{ describe, expect, it, vi }`. No type-only imports, no `MockInstance`/`Mock` types, no `vi.hoisted` mock-factory imports. The migration is therefore mechanical — a single regex rewrite per file with no shape changes.
The drift went unnoticed because nothing in CI flags direct `vitest` imports. The companion gate for `export *` (rule 10 / §6a) caught analogous drift; this change adds the equivalent gate for the runner contract.
## Goals / Non-Goals
**Goals:**
- Migrate all 19 violator packages to `from "@suaveplan/testing/runner"`.
- Codify the rule as a `monorepo-structure` requirement with an explicit allowlist of exempt testing-infra packages.
- Add a CI grep gate that prevents regression (mirrors the §13 barrel-export gate).
- Document the rule in `CLAUDE.md` (Critical Rules) and `openspec/AGENTS.md` so it is enforced at code-review time and applied during future package migrations.
**Non-Goals:**
- Not changing the runner subpath itself — the conditional export already works and is exercised by 107 packages.
- Not migrating the 5 testing-infra packages (`dev/testing`, `dev/testing-dom`, `dev/testing-e2e`, `dev/testing-integration`, `dev/testing-integration-step-ca`). They author or extend the wrapper and MUST import from `vitest` / `bun:test` directly.
- Not adding a `bun:test` re-export for non-infra packages — the runner subpath's `bun` condition handles that automatically.
- Not changing test behaviour, test counts, coverage thresholds, or runner configuration (`vitest.config.ts`).
## Decisions
### Decision: Single-regex rewrite, per file
`from ['"]vitest['"]` → `from "@suaveplan/testing/runner"`. Apply with `bunx biome` after the rewrite to normalise import-name ordering. Verify per package with `bunx turbo lint typecheck test:coverage --filter=@suaveplan/<pkg>` — coverage MUST stay at 100% on touched modules (CLAUDE.md pre-publish gate).
**Alternative considered:** AST-based codemod (ts-morph). Rejected — the violation set is `{ describe, expect, it, vi }` with no destructure variations and no edge cases; a codemod is overkill for ~150 lines of replacement.
### Decision: Allowlist via package-name array, not path glob
The exemption list lives in the CI gate as `EXEMPT_PACKAGES = ["@suaveplan/testing", "@suaveplan/testing-dom", "@suaveplan/testing-e2e", "@suaveplan/testing-integration", "@suaveplan/testing-integration-step-ca"]` and is read from each package's `package.json#name`. Glob-on-path was considered but rejected — packages may move folders (the `dev/` parent is itself a recent reshuffle) and the npm name is the stable identity per `MANIFEST.md`.
### Decision: CI gate as a standalone script, not a Biome rule
A custom Biome rule would be ideal but Biome's plugin API is not yet stable enough for repo-local rules at our Biome version. Instead, ship `scripts/lint/check-test-runner-imports.ts` (Bun-native) and wire it into `turbo.json` under a new `lint:test-runner-imports` task that runs alongside the existing barrel-export check. The script:
1. Walks `packages/*/*/package.json` to collect `name`s.
2. Skips entries in `EXEMPT_PACKAGES`.
3. For each remaining package, greps `src/**/*.{ts,tsx}` for `from ['"]vitest['"]` and `from ['"]bun:test['"]`.
4. Exits non-zero with a per-file error list when any are found.
Runtime budget: <1s on the full repo (the existing barrel grep is ~400ms).
**Alternative considered:** ESLint with `no-restricted-imports`. Rejected — the repo uses Biome, not ESLint. Adding ESLint just for one rule is dependency bloat.
### Decision: Migration order — by domain, not alphabetical
Migrate one domain at a time so each PR-equivalent unit is a coherent set: `bitpacker/*` (7 pkgs) → `network/*` (7 pkgs) → `crypto/*` (2 pkgs) → `media/voice` + `storage/storage` + `audio/third-party-elevenlabs` (3 pkgs). Verification gate runs after each domain. This bounds blast radius if a hidden vitest-only API surface appears (none expected, but cheap insurance).
## Risks / Trade-offs
- **[Risk] A test file imports a vitest symbol the runner barrel doesn't re-export.** → Mitigation: audit confirmed the surface is `{ describe, expect, it, vi }` only — all four are already re-exported. If a future violator emerges with a missing symbol, extend `packages/testing/testing/src/runner/vitest.ts` to re-export it (additive, no breaking change).
- **[Risk] The `bun` condition resolves to `bun-test.ts`, which may not export a symbol present in the vitest path.** → Mitigation: the dual-runner conformance test (`runner.spec-conformance.test.ts`) already pins surface parity; no migrated package consumes a vitest-only API today. If divergence shows up in the future, the conformance test fails, not the migrated package.
- **[Risk] `bunx biome format` reorders imports in a way that breaks existing test isolation (e.g., side-effect import order).** → Mitigation: test files have no side-effect imports today (verified by spot-check). Per-package `bunx turbo test:coverage` after migration catches any breakage immediately.
- **[Trade-off] The CI grep gate doesn't catch dynamic imports (`await import("vitest")`).** → Accepted: dynamic imports of vitest in test files are vanishingly rare and would be obvious in code review. The cost of a full AST scan is not justified.
## Migration Plan
Per domain:
1. Run rewrite (`grep -rl 'from "vitest"' packages/<domain> | xargs sed -i 's|from "vitest"|from "@suaveplan/testing/runner"|'`).
2. `bunx biome check --write packages/<domain>` to normalise.
3. `bunx turbo lint typecheck test:coverage --filter=./packages/<domain>/*` — must be green at 100%.
4. Commit per domain (`refactor(<domain>): use canonical @suaveplan/testing/runner imports`).
After all five domain waves are green, ship the rule + CI gate in a single follow-up commit. Rollback: a single `git revert` per domain commit; the CI gate commit is independently revertable.