Files
2026-05-27 23:29:53 +01:00

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

  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

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.