8.1 KiB
8.1 KiB
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Pre-flight
- 1.1 Re-run violator audit to confirm the 19-package list is still current:
grep -rlE "from ['\"]vitest['\"]" packages --include="*.ts" --include="*.tsx" | grep -v "vite.config\|vitest.config" | sed -E 's|^packages/([^/]+/[^/]+)/.*|\1|' | sort -u - 1.2 Re-run the import-name surface audit to confirm only
{ describe, expect, it, vi }are in use across the 19 violators (no surpriseMockInstance/Mocktype imports) - 1.3 Snapshot baseline:
bunx turbo lint typecheck test:coverageis green (or document the current red state) so post-migration deltas are attributable- Skipped full-monorepo coverage baseline; per-wave gates per CLAUDE.md are stricter and any failure is attributable to that wave's mechanical change.
2. Wave A — bitpacker (7 packages)
- 2.1
bitpacker/bitpacker-compressed: rewritefrom "vitest"→from "@suaveplan/testing/runner"insrc/**/*.test.ts - 2.2
bitpacker/bitpacker-crypto: rewrite imports - 2.3
bitpacker/bitpacker-delta: rewrite imports - 2.4
bitpacker/bitpacker-network: rewrite imports - 2.5
bitpacker/bitpacker-schema: rewrite imports - 2.6
bitpacker/bitpacker-strategies: rewrite imports - 2.7
bitpacker/bitpacker-streaming: rewrite imports - 2.8
bunx biome check --write packages/bitpackerto normalise import ordering — 6 files fixed - 2.9
bunx turbo lint typecheck test:coverage --filter=./packages/bitpacker/*— must be green at 100% on touched files — 46/46 turbo tasks green; tests: 50/50 (compressed), 16/16 (crypto/superseded), 49/49 + 65/65 + 22/22 (delta), 72/72 (network), 79+131+151+30 (schema), 203/203 (strategies), 66/66 (streaming) - 2.10 Commit Wave A:
refactor(bitpacker): use canonical @suaveplan/testing/runner imports(awaiting user approval to commit)
3. Wave B — network (7 packages)
- 3.1
network/network: rewrite imports - 3.2
network/network-failover: rewrite imports - 3.3
network/network-governance: rewrite imports - 3.4
network/network-plugin-protocol: rewrite imports - 3.5
network/network-plugin-registry: rewrite imports - 3.6
network/network-plugin-webrtc: rewrite imports - 3.7
network/network-topology: rewrite imports - 3.8
bunx biome check --write packages/networkto normalise — no fixes needed - 3.9
bunx turbo lint typecheck test:coverage --filter=./packages/network/*— must be green at 100% — 47/47 turbo tasks green - 3.10 Commit Wave B:
refactor(network): use canonical @suaveplan/testing/runner imports(awaiting user approval to commit)
4. Wave C — crypto (2 packages)
- 4.1
crypto/crypto: rewrite imports - 4.2
crypto/crypto-cli: rewrite imports - 4.3
bunx biome check --write packages/crypto/crypto packages/crypto/crypto-clito normalise — 7 files fixed - 4.4
bunx turbo lint typecheck test:coverage --filter=@suaveplan/crypto --filter=@suaveplan/crypto-cli— must be green at 100% — 20/20 turbo tasks green; crypto: 380 tests, crypto-cli: 17 tests - 4.5 Commit Wave C:
refactor(crypto): use canonical @suaveplan/testing/runner imports(awaiting user approval to commit)
5. Wave D — remaining (3 packages)
- 5.1
media/voice: rewrite imports - 5.2
storage/storage: rewrite imports - 5.3
audio/third-party-elevenlabs(npm name@suaveplan/third-party-elevenlabs): rewrite imports - 5.4
bunx biome check --write packages/audio/voice packages/storage/storage packages/audio/third-party-elevenlabsto normalise — no fixes needed - 5.5
bunx turbo lint typecheck test --filter=@suaveplan/voice --filter=@suaveplan/storage --filter=@suaveplan/third-party-elevenlabs— voice + storage green (12/12 tasks, 208 storage tests + voice tests).@suaveplan/third-party-elevenlabshas a pre-existing build defect (src/index.tsis missing — the package is an in-progress scaffold tracked by the active OpenSpec changethird-party-elevenlabs); out of scope for this change. My migration only edited.test.tsfiles and biome accepted them. - 5.6 Commit Wave D:
refactor: use canonical @suaveplan/testing/runner imports in voice/storage/third-party-elevenlabs(awaiting user approval to commit)
6. CI gate
- 6.1 Create
scripts/lint/check-test-runner-imports.ts(Bun-native) that walkspackages/*/*/package.json, skips packages whosenameis in the exempt allowlist (@suaveplan/testing,@suaveplan/testing-dom,@suaveplan/testing-e2e,@suaveplan/testing-integration,@suaveplan/testing-integration-step-ca), grepssrc/**/*.{ts,tsx}forfrom ['"]vitest['"]andfrom ['"]bun:test['"], and exits non-zero with a per-file error list when any are found - 6.2 Add a unit test for the script: feed it a fake-fs with a deliberate violation and assert the non-zero exit + correct error message —
scripts/lint/check-test-runner-imports.test.ts, 8 tests, all pass - 6.3 Add a
lint:test-runner-importstask to rootturbo.json(and corresponding rootpackage.jsonscript) that invokes the new script — added//#lint:test-runner-imports(cache=true, scoped inputs) + rootlint:test-runner-importsscript - 6.4 Wire the new task into the existing
linttask pipeline sobunx turbo lintruns it — rootlintscript now runsbunx turbo lint lint:test-runner-imports - 6.5 Run the gate locally to confirm it passes after Waves A–D and fails when a single violation is reintroduced — verified: clean=exit 0, injected violation=exit 1 with precise file:line:source diagnostic, restored=exit 0
- 6.6 Commit:
feat(ci): grep gate forbidding direct vitest/bun:test imports outside testing-infra allowlist(awaiting user approval to commit)
7. Documentation
- 7.1 Update
CLAUDE.mdCritical Rules: add new rule (e.g., "11. NEVER import test-runner primitives directly fromvitestorbun:testin non-exempt packages") with the verification grep and exempt-allowlist call-out — added as Critical Rule 11 - 7.2 Update
openspec/AGENTS.mdwith a sibling rule next to §6a (call it §6b) that mirrors the §6a phrasing pattern (rule + reason + verification grep + migration-prerequisite clause) — expanded existing §7 "Test runner imports — mandatory" with allowlist + migration prerequisite + verification grep + 19-package drift note; added matching row to §0a anti-pattern table - 7.3 Update
openspec/AGENTS.md§13 verification step to includebun scripts/lint/check-test-runner-imports.tsalongside the existing barrel-export grep — added §13 step 4b (per-package grep) right after the §6a barrel-shape scan, with cross-reference to the repo-wide CI gate - 7.4 Cross-link the new rule from the
enterprise-package-migrationskill so future port work catches directvitestimports during the migration commit, not as a follow-up — added row 9 to the migration parity checklist - 7.5 Commit:
docs: codify canonical-test-runner-imports rule in CLAUDE.md and AGENTS.md(awaiting user approval to commit)
8. Archive
- 8.1 Confirm
bunx turbo lint typecheck test:coverageis green across the full monorepo - 8.2 Confirm
bun scripts/lint/check-test-runner-imports.tsexits 0 on the full monorepo - 8.3 Fold
specs/monorepo-structure/spec.mddelta intoopenspec/specs/monorepo-structure/spec.md(append the new requirement under## Requirements) - 8.4 Move the change folder to
openspec/archive/2026-05-03-enforce-canonical-test-runner-imports/ - 8.5 Update
STATUS.mdandnow.mdwith the archive entry