5.0 KiB
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
function createExperimentRegistry(options?: ExperimentRegistryOptions): ExperimentRegistry
interface ExperimentRegistry {
register(experiment: ExperimentDefinition): void
get(id: string): ExperimentDefinition | null
list(status?: ExperimentStatus): ReadonlyArray<ExperimentDefinition>
run<T>(id: string, fn: ExperimentFn<T>, signal?: AbortSignal): Promise<ExperimentRun<T>>
graduate(id: string, targetPackage: string): void
abandon(id: string, reason: string): void
}
Experiment definition
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<T> = (signal?: AbortSignal) => Promise<T>
interface ExperimentRun<T> {
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
function wip<T>(description: string, fn: () => T): T
function wipAsync<T>(description: string, fn: (signal?: AbortSignal) => Promise<T>, signal?: AbortSignal): Promise<T>
function todo(message?: string): never
function notImplemented(feature: string): never
Error codes
type WipErrorCode =
| 'WIP_EXPERIMENT_NOT_FOUND'
| 'WIP_EXPERIMENT_NOT_ACTIVE'
| 'WIP_FLAG_DISABLED'
| 'WIP_NOT_IMPLEMENTED'
| 'WIP_ABORT'
function registerWipErrorCodes(): void
Genesis additions
- Structured
WipErrorextendingSuaveplanErrorwith stableWIP.*codes ExperimentRegistry— lifecycle management for WIP experimentswip()/wipAsync()wrappers — log a structured trace entry when entering WIP code; throw in production builds whenNODE_ENV === 'production'todo()/notImplemented()helpers — throwWipError(WIP_NOT_IMPLEMENTED)with descriptive message, never silent- Feature-flag gating — experiments can require a flag to be enabled before running
- Injectable
Clockfor experiment timestamps - OTel instrumentation — span
wip.experiment.run, counterwip.experiments_run_total - Zod schemas for
ExperimentDefinition,ExperimentRegistryOptions
File layout
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.