# OpenSpec Change: enterprise-wip - **Change ID**: enterprise-wip - **Package**: `@suaveplan/wip` - **Category**: universal/dev - **Target path**: `universal/dev/wip` - **Status**: PROPOSED - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/wip.md` --- ## Summary Deliver `@suaveplan/wip` on the genesis branch from scratch at enterprise quality. The package provides a work-in-progress experiments sandbox: a structured home for exploratory code, feature-flag-gated experiments, and proof-of-concept implementations that are not yet ready for a dedicated package. Genesis adds structured errors via `@suaveplan/error`, Zod schemas for experiment metadata, OTel instrumentation, `AbortSignal` on async experiments, and an `ExperimentRegistry` for tracking active experiments with lifecycle management (draft, active, graduated, abandoned). --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | Base class for `WipError`; stable error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock`, `EventBusLike` | | `@suaveplan/events` (`workspace:^`) | Event bus for experiment lifecycle events | | `@suaveplan/feature-flags` (`workspace:^`) | Feature-flag gating for experiments | | `@suaveplan/logger` (`workspace:^`) | Structured logging | | `zod` (`catalog:forms`) | Zod schemas for experiment metadata | | `@opentelemetry/api` (`catalog:observability`) | Spans on experiment execution | | `tslib` (`catalog:build`) | Runtime helpers | Dev deps: `vitest`, `@vitest/coverage-istanbul` (all `catalog:testing`). --- ## Public API surface ### Core ```ts function createExperimentRegistry(options?: ExperimentRegistryOptions): ExperimentRegistry interface ExperimentRegistry { register(experiment: ExperimentDefinition): void get(id: string): ExperimentDefinition | null list(status?: ExperimentStatus): ReadonlyArray run(id: string, fn: ExperimentFn, signal?: AbortSignal): Promise> graduate(id: string, targetPackage: string): void abandon(id: string, reason: string): void } ``` ### Experiment definition ```ts interface ExperimentDefinition { id: string name: string description: string author?: string createdAt?: number status: ExperimentStatus targetPackage?: string // where this will graduate to flagId?: string // optional feature flag gate tags?: string[] } type ExperimentStatus = 'draft' | 'active' | 'graduated' | 'abandoned' type ExperimentFn = (signal?: AbortSignal) => Promise interface ExperimentRun { readonly experimentId: string readonly result: T readonly durationMs: number readonly timestamp: number } interface ExperimentRegistryOptions { logger?: LoggerLike clock?: Clock eventBus?: EventBusLike flagManager?: unknown // FlagManager from @suaveplan/feature-flags } ``` ### Utilities ```ts function wip(description: string, fn: () => T): T function wipAsync(description: string, fn: (signal?: AbortSignal) => Promise, signal?: AbortSignal): Promise function todo(message?: string): never function notImplemented(feature: string): never ``` ### Error codes ```ts type WipErrorCode = | 'WIP_EXPERIMENT_NOT_FOUND' | 'WIP_EXPERIMENT_NOT_ACTIVE' | 'WIP_FLAG_DISABLED' | 'WIP_NOT_IMPLEMENTED' | 'WIP_ABORT' function registerWipErrorCodes(): void ``` --- ## Genesis additions 1. **Structured `WipError`** extending `SuaveplanError` with stable `WIP.*` codes 2. **`ExperimentRegistry`** — lifecycle management for WIP experiments 3. **`wip()` / `wipAsync()` wrappers** — log a structured trace entry when entering WIP code; throw in production builds when `NODE_ENV === 'production'` 4. **`todo()` / `notImplemented()` helpers** — throw `WipError(WIP_NOT_IMPLEMENTED)` with descriptive message, never silent 5. **Feature-flag gating** — experiments can require a flag to be enabled before running 6. **Injectable `Clock`** for experiment timestamps 7. **OTel instrumentation** — span `wip.experiment.run`, counter `wip.experiments_run_total` 8. **Zod schemas** for `ExperimentDefinition`, `ExperimentRegistryOptions` --- ## File layout ```text universal/dev/wip/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/ index.ts types/ common.ts common.md core/ registry/ registry.ts registry.md registry.types.ts registry.test.ts index.ts utils/ helpers.ts helpers.md helpers.test.ts tests/ integration.test.ts ``` --- ## Impact **Downstream packages**: Developer tooling only. Should never be imported from production packages — the `wip()` helper throws in production builds as a safety guard. **Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/feature-flags`, `@suaveplan/logger` must be published.