## 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. Catalog setup - [ ] 1.1 Add `autocannon` to root `package.json` `catalogs.testing` (k6 runs via the `grafana/k6` container; no npm entry needed) - [ ] 1.2 Run `bun install`; confirm lockfile updates cleanly ## 2. Package skeleton — `@suaveplan/testing-load` - [ ] 2.1 Create `packages/testing/testing-load/` with `package.json` (version `0.1.0`, `type: "module"`, `sideEffects: false`, `@suaveplan/types` workspace dep, external catalog deps only) - [ ] 2.2 Create `tsconfig.lib.json` extending `@suaveplan/typescript-config/library.json` - [ ] 2.3 Create `vite.config.ts` (preserveModules, ESM only) - [ ] 2.4 Create `vitest.config.ts` consuming `@suaveplan/testing/config` once available; thresholds at 100/100/100/100 (istanbul) - [ ] 2.5 Create `README.md` with purpose, install, quick-start, error-code index, links to module `.md` files - [ ] 2.6 Subpath exports in `package.json` for every feature module per `openspec/AGENTS.md` §6 ## 3. Public API — scenario, driver, runner - [ ] 3.1 `src/scenario/scenario.ts` — `defineLoadScenario`, `LoadScenario`, `LoadScenarioSpec`; Zod schemas in `scenario.schemas.ts` - [ ] 3.2 `src/scenario/presets.ts` — `smoke`, `load`, `stress`, `spike` constants composing vus/stages/duration - [ ] 3.3 `src/driver/driver.ts` — `LoadDriver` interface, `LoadSummary` normalised shape - [ ] 3.4 `src/driver/k6-driver.ts` — k6 implementation; injectable `exec` (testcontainers) + `fetch` for self-testability - [ ] 3.5 `src/driver/autocannon-driver.ts` — autocannon implementation; in-process Node fallback - [ ] 3.6 `src/runner/run-load-scenario.ts` — `runLoadScenario(scenario, opts)`; resolves driver default to k6 if reachable, autocannon otherwise; honours `AbortSignal` - [ ] 3.7 `src/thresholds/assert-thresholds.ts` — `assertThresholds(summary)`; throws `TestingLoadError("TESTING_LOAD.THRESHOLD_VIOLATION", …)` listing every failed predicate ## 4. Errors and observability - [ ] 4.1 `src/errors/testing-load-error.ts` — `TestingLoadError extends Error` with `{ code, cause?, context? }` - [ ] 4.2 `src/errors/codes.ts` — `TESTING_LOAD.THRESHOLD_VIOLATION`, `TESTING_LOAD.DRIVER_FAILED`, `TESTING_LOAD.CONFIG_INVALID`, `TESTING_LOAD.DRIVER_UNAVAILABLE`, `TESTING_LOAD.ABORTED` - [ ] 4.3 OTel counters/histograms via `@opentelemetry/api` per existing `testing/spec.md` pattern; spans for `runLoadScenario` only ## 5. Tests, docs, schemas - [ ] 5.1 Co-locate `*.test.ts` per implementation file; 100% Istanbul coverage (statements / branches / functions / lines) - [ ] 5.2 Co-locate `*.md` per implementation file (≥ 200 words, simple + advanced examples, API reference, implementation notes) per `openspec/AGENTS.md` §4 - [ ] 5.3 Co-locate `*.schemas.ts` per implementation file; tree-shake test proving schemas don't bloat functional bundle - [ ] 5.4 Property tests (fast-check) for `assertThresholds` predicate evaluation, scenario merge associativity - [ ] 5.5 Mitata benchmarks under `src/__benchmarks__/` for scenario-build and threshold-evaluation hot paths ## 6. App integration — `*.smoke.load.ts` - [ ] 6.1 `apps/testbed/tests/load/healthz.smoke.load.ts` — smoke scenario for `GET /healthz` - [ ] 6.2 One `*.smoke.load.ts` per route declared in `apps/testbed/src/routes.ts` - [ ] 6.3 `apps/websocket-gateway/tests/load/connection.smoke.load.ts` — websocket-fan-out smoke scenario - [ ] 6.4 Each app's `package.json` exposes `test:load:smoke` invoking its smoke files via the package's own runner ## 7. CI integration - [ ] 7.1 Nightly job: run every `*.smoke.load.ts` against the app's Docker staging stack - [ ] 7.2 Failure on any threshold violation breaks the build - [ ] 7.3 Weekly job (or manual workflow_dispatch): run `load`, `stress`, `spike` modes against staging - [ ] 7.4 Cross-link smoke result into the release-readiness gate (audit §7) once that gate lands ## 8. Spec deltas and validation - [ ] 8.1 `openspec validate enterprise-testing-load-perf --type change` passes - [ ] 8.2 Fold `specs/testing-load/spec.md` ADDED Requirements into a new `openspec/specs/testing-load/spec.md` - [ ] 8.3 Fold `specs/testing/spec.md` ADDED Requirement into the existing `openspec/specs/testing/spec.md` - [ ] 8.4 Move this change folder to `openspec/archive/-enterprise-testing-load-perf/` ## 9. Pre-publish gate and publish - [ ] 9.1 `bunx turbo lint typecheck test --filter=@suaveplan/testing-load` green - [ ] 9.2 `bunx turbo test:coverage --filter=@suaveplan/testing-load` reports 100% statements / branches / functions / lines - [ ] 9.3 `bun scripts/publish.ts --package @suaveplan/testing-load --dry-run` produces a sane diff - [ ] 9.4 `bun scripts/publish.ts --package @suaveplan/testing-load` — publish `0.1.0` to Verdaccio