# Tasks: enterprise-wip **Change ID**: enterprise-wip **Package**: `@suaveplan/wip` **Target path**: `universal/dev/wip` **Prerequisite packages on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/feature-flags`, `@suaveplan/logger` --- ## 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. Scaffold - [ ] Create `universal/dev/wip/` with `src/`, `tests/`, and feature subdirectories per the layout in `proposal.md`. - [ ] Write `package.json` at version `0.1.0`: - `"type": "module"`, `"sideEffects": false` - `exports` map: `"."` barrel + `"./core/registry/registry"`, `"./utils/helpers"` - `dependencies`: `@suaveplan/error workspace:^`, `@suaveplan/types workspace:^`, `@suaveplan/events workspace:^`, `@suaveplan/feature-flags workspace:^`, `@suaveplan/logger workspace:^`, `zod catalog:forms`, `@opentelemetry/api catalog:observability`, `tslib catalog:build` - `devDependencies`: `vitest catalog:testing`, `@vitest/coverage-istanbul catalog:testing`, `@suaveplan/testing workspace:^` - [ ] Write `tsconfig.json` extending `@suaveplan/typescript-config/library.json`. - [ ] Write `vitest.config.ts` using `createTestConfig()`. - [ ] Add `lint`, `typecheck`, `test`, `test:coverage`, `build`, `docs:check` scripts. --- ## 2. Types and error codes - [ ] Define all public types in `src/types/common.ts`: `ExperimentDefinition`, `ExperimentStatus`, `ExperimentFn`, `ExperimentRun`, `ExperimentRegistryOptions`, `ExperimentRegistry`. - [ ] Write `src/types/common.md` (≥200 words, simple + advanced examples). - [ ] Define error codes in `src/error-codes.ts`: `WipErrorCode` union, metadata, `registerWipErrorCodes()`. - [ ] Write Zod schemas in `src/types/schemas.ts` + `src/types/schemas.md`. --- ## 3. Helper utilities (`src/utils/helpers.ts`) - [ ] Implement `wip(description, fn)`: - In production (`process.env.NODE_ENV === 'production'`): throw `WipError(WIP_NOT_IMPLEMENTED)` immediately — WIP code must never reach production. - In development: log a `logger.warn` or `console.warn` with the description, then call `fn()`. - Return result of `fn()`. - [ ] Implement `wipAsync(description, fn, signal?)`: async version; same production guard. - [ ] Implement `todo(message?)`: always throws `WipError(WIP_NOT_IMPLEMENTED)` with optional message. Return type is `never`. - [ ] Implement `notImplemented(feature)`: throws `WipError(WIP_NOT_IMPLEMENTED)` with feature name. Return type is `never`. - [ ] Write `helpers.test.ts` (≤500 lines): `wip` in dev executes fn, `wip` in prod throws, `wipAsync` in dev resolves, `todo` throws, `notImplemented` throws. - [ ] Write `helpers.md` (≥200 words). --- ## 4. Experiment registry (`src/core/registry/`) - [ ] Implement `createExperimentRegistry(options?)`: - Stores experiments in `Map`. - Validates options with Zod. - [ ] Implement `registry.register(experiment)`: - Validates with `ExperimentDefinitionSchema`. - Throws `WipError(WIP_EXPERIMENT_NOT_FOUND)` if ID already registered (idempotency: re-registering with same ID is a no-op). - [ ] Implement `registry.get(id)` — returns experiment or `null`. - [ ] Implement `registry.list(status?)` — returns experiments, optionally filtered by status. - [ ] Implement `registry.run(id, fn, signal?)`: - Throws `WipError(WIP_EXPERIMENT_NOT_FOUND)` if experiment not registered. - Throws `WipError(WIP_EXPERIMENT_NOT_ACTIVE)` if experiment status is not `active`. - If `experiment.flagId` is set, check via `options.flagManager`; throw `WipError(WIP_FLAG_DISABLED)` if flag is off. - Calls `fn(signal)`, measures duration, returns `ExperimentRun`. - OTel span `wip.experiment.run`, attribute `experiment.id`; counter `wip.experiments_run_total`. - [ ] Implement `registry.graduate(id, targetPackage)` — updates status to `graduated`, sets `targetPackage`. - [ ] Implement `registry.abandon(id, reason)` — updates status to `abandoned`. - [ ] Write `registry.test.ts` (≤500 lines): register, run, flag-gated run, graduate, abandon, status filtering. - [ ] Write `registry.md` (≥200 words). --- ## 5. Integration tests (`tests/integration.test.ts`) - [ ] Register 3 experiments, run active one, verify result returned. - [ ] Graduate experiment, confirm it can no longer run (not active). - [ ] Abandon experiment, confirm it can no longer run. - [ ] Feature-flag-gated experiment: disabled flag → `WIP_FLAG_DISABLED`. --- ## 6. Docs - [ ] All per-file `.md` files: `common.md`, `schemas.md`, `helpers.md`, `registry.md`. - [ ] `universal/dev/wip/README.md`: purpose (development-only sandbox), installation, usage, WARNING about production guard, API section. --- ## 7. Verify and publish - [ ] `bunx turbo lint --filter=@suaveplan/wip` — zero errors. - [ ] `bunx turbo typecheck --filter=@suaveplan/wip` — zero errors. - [ ] `bunx turbo test --filter=@suaveplan/wip` — all tests pass. - [ ] `bunx turbo test:coverage --filter=@suaveplan/wip` — 100% on all touched modules. - [ ] `bun run docs:check --filter=@suaveplan/wip` — zero errors. - [ ] `bun scripts/publish.ts --package @suaveplan/wip`. - [ ] Update `CLAUDE.md` package listing. - [ ] Archive: move `openspec/changes/enterprise-wip/` to `openspec/archive/2026-04-24-enterprise-wip/`.