Initial Commit
This commit is contained in:
166
openspec/changes/enterprise-wip/proposal.md
Normal file
166
openspec/changes/enterprise-wip/proposal.md
Normal file
@@ -0,0 +1,166 @@
|
||||
# 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<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
|
||||
|
||||
```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<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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```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.
|
||||
Reference in New Issue
Block a user