5.8 KiB
5.8 KiB
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 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. Scaffold
- Create
universal/dev/wip/withsrc/,tests/, and feature subdirectories per the layout inproposal.md. - Write
package.jsonat version0.1.0:"type": "module","sideEffects": falseexportsmap:"."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:builddevDependencies:vitest catalog:testing,@vitest/coverage-istanbul catalog:testing,@suaveplan/testing workspace:^
- Write
tsconfig.jsonextending@suaveplan/typescript-config/library.json. - Write
vitest.config.tsusingcreateTestConfig(). - Add
lint,typecheck,test,test:coverage,build,docs:checkscripts.
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:WipErrorCodeunion, metadata,registerWipErrorCodes(). - Write Zod schemas in
src/types/schemas.ts+src/types/schemas.md.
3. Helper utilities (src/utils/helpers.ts)
- Implement
wip<T>(description, fn):- In production (
process.env.NODE_ENV === 'production'): throwWipError(WIP_NOT_IMPLEMENTED)immediately — WIP code must never reach production. - In development: log a
logger.warnorconsole.warnwith the description, then callfn(). - Return result of
fn().
- In production (
- Implement
wipAsync<T>(description, fn, signal?): async version; same production guard. - Implement
todo(message?): always throwsWipError(WIP_NOT_IMPLEMENTED)with optional message. Return type isnever. - Implement
notImplemented(feature): throwsWipError(WIP_NOT_IMPLEMENTED)with feature name. Return type isnever. - Write
helpers.test.ts(≤500 lines):wipin dev executes fn,wipin prod throws,wipAsyncin dev resolves,todothrows,notImplementedthrows. - Write
helpers.md(≥200 words).
4. Experiment registry (src/core/registry/)
- Implement
createExperimentRegistry(options?):- Stores experiments in
Map<string, ExperimentDefinition>. - Validates options with Zod.
- Stores experiments in
- 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).
- Validates with
- Implement
registry.get(id)— returns experiment ornull. - Implement
registry.list(status?)— returns experiments, optionally filtered by status. - Implement
registry.run<T>(id, fn, signal?):- Throws
WipError(WIP_EXPERIMENT_NOT_FOUND)if experiment not registered. - Throws
WipError(WIP_EXPERIMENT_NOT_ACTIVE)if experiment status is notactive. - If
experiment.flagIdis set, check viaoptions.flagManager; throwWipError(WIP_FLAG_DISABLED)if flag is off. - Calls
fn(signal), measures duration, returnsExperimentRun<T>. - OTel span
wip.experiment.run, attributeexperiment.id; counterwip.experiments_run_total.
- Throws
- Implement
registry.graduate(id, targetPackage)— updates status tograduated, setstargetPackage. - Implement
registry.abandon(id, reason)— updates status toabandoned. - 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
.mdfiles: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.mdpackage listing. - Archive: move
openspec/changes/enterprise-wip/toopenspec/archive/2026-04-24-enterprise-wip/.