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

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 status reports nothing) and no in-flight worktrees with uncommitted work (git worktree list then git status in 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.md matches find packages -maxdepth 3 -name package.json count. Drift here means a prior change archived without regenerating the manifest.

1. Scaffold

  • Create universal/dev/wip/ with src/, tests/, and feature subdirectories per the layout in proposal.md.
  • Write package.json at version 0.1.0:
    • "type": "module", "sideEffects": false
    • exports map: "." 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:build
    • devDependencies: vitest catalog:testing, @vitest/coverage-istanbul catalog:testing, @suaveplan/testing workspace:^
  • Write tsconfig.json extending @suaveplan/typescript-config/library.json.
  • Write vitest.config.ts using createTestConfig().
  • Add lint, typecheck, test, test:coverage, build, docs:check scripts.

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: WipErrorCode union, 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'): throw WipError(WIP_NOT_IMPLEMENTED) immediately — WIP code must never reach production.
    • In development: log a logger.warn or console.warn with the description, then call fn().
    • Return result of fn().
  • Implement wipAsync<T>(description, fn, signal?): async version; same production guard.
  • Implement todo(message?): always throws WipError(WIP_NOT_IMPLEMENTED) with optional message. Return type is never.
  • Implement notImplemented(feature): throws WipError(WIP_NOT_IMPLEMENTED) with feature name. Return type is never.
  • Write helpers.test.ts (≤500 lines): wip in dev executes fn, wip in prod throws, wipAsync in dev resolves, todo throws, notImplemented throws.
  • Write helpers.md (≥200 words).

4. Experiment registry (src/core/registry/)

  • Implement createExperimentRegistry(options?):
    • Stores experiments in Map<string, ExperimentDefinition>.
    • Validates options with Zod.
  • 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).
  • Implement registry.get(id) — returns experiment or null.
  • 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 not active.
    • If experiment.flagId is set, check via options.flagManager; throw WipError(WIP_FLAG_DISABLED) if flag is off.
    • Calls fn(signal), measures duration, returns ExperimentRun<T>.
    • OTel span wip.experiment.run, attribute experiment.id; counter wip.experiments_run_total.
  • Implement registry.graduate(id, targetPackage) — updates status to graduated, sets targetPackage.
  • Implement registry.abandon(id, reason) — updates status to abandoned.
  • 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 .md files: 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.md package listing.
  • Archive: move openspec/changes/enterprise-wip/ to openspec/archive/2026-04-24-enterprise-wip/.