Files
2026-05-27 23:29:53 +01:00

8.1 KiB
Raw Permalink Blame History

0. Pre-flight (non-negotiable)

  • 0.1 Confirm clean working tree (git status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in 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.md matches find packages -maxdepth 3 -name package.json count. 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 surprise MockInstance / Mock type imports)
  • 1.3 Snapshot baseline: bunx turbo lint typecheck test:coverage is 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: rewrite from "vitest" → from "@suaveplan/testing/runner" in src/**/*.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/bitpacker to 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/network to 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-cli to 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-elevenlabs to 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-elevenlabs has a pre-existing build defect (src/index.ts is missing — the package is an in-progress scaffold tracked by the active OpenSpec change third-party-elevenlabs); out of scope for this change. My migration only edited .test.ts files 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 walks packages/*/*/package.json, skips packages whose name is in the exempt allowlist (@suaveplan/testing, @suaveplan/testing-dom, @suaveplan/testing-e2e, @suaveplan/testing-integration, @suaveplan/testing-integration-step-ca), greps src/**/*.{ts,tsx} for from ['"]vitest['"] and from ['"]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-imports task to root turbo.json (and corresponding root package.json script) that invokes the new script — added //#lint:test-runner-imports (cache=true, scoped inputs) + root lint:test-runner-imports script
  • 6.4 Wire the new task into the existing lint task pipeline so bunx turbo lint runs it — root lint script now runs bunx 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.md Critical Rules: add new rule (e.g., "11. NEVER import test-runner primitives directly from vitest or bun:test in non-exempt packages") with the verification grep and exempt-allowlist call-out — added as Critical Rule 11
  • 7.2 Update openspec/AGENTS.md with 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 include bun scripts/lint/check-test-runner-imports.ts alongside 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-migration skill so future port work catches direct vitest imports 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:coverage is green across the full monorepo
  • 8.2 Confirm bun scripts/lint/check-test-runner-imports.ts exits 0 on the full monorepo
  • 8.3 Fold specs/monorepo-structure/spec.md delta into openspec/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.md and now.md with the archive entry