# OpenSpec Change: enterprise-timing - **Change ID**: enterprise-timing - **Package**: `@suaveplan/timing` - **Category**: universal - **Target path**: `packages/universal/timing` - **Status**: IN PROGRESS - **Date**: 2026-04-18 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/timing.md` ## Summary Greenfield implementation of `@suaveplan/timing` for the genesis branch. The existing main-branch timing package provides the baseline public-API surface to preserve; this change delivers enterprise-grade timing and scheduling utilities — stopwatch, throttle/debounce, scheduler, exponential decay, and vector clock — with injectable clock, `AbortSignal` support, structured errors, Zod schemas, property-based tests, OTel instrumentation, and benchmarks. ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. ## Available workspace deps on genesis | Package | Available | |---------|-----------| | `@suaveplan/error` | ✅ | | `@suaveplan/types` | ✅ | | `@suaveplan/events` | ✅ | | `@suaveplan/streams` | ❌ not yet built — not required | | `@suaveplan/opentelemetry` | ❌ not yet built — use `@opentelemetry/api` directly | | `@suaveplan/feature-flags` | ❌ not yet built — skip | | `@suaveplan/schema-registry` | ❌ not yet built — export Zod schemas directly | External deps (via catalog): - `zod` → `catalog:forms` - `@opentelemetry/api` → `catalog:observability` - `tslib` → `catalog:build` Dev deps (via catalog): - `vitest`, `@vitest/coverage-istanbul` → `catalog:testing` - `fast-check` → `catalog:testing` - `mitata` → `catalog:testing` ## Preserved public API surface (from main branch) All of the following must be re-exported from the genesis build. ### Decay module (`src/decay/`) - `createDecay(opts)` — returns a `Decay` instance with `.tick(elapsed)`, `.reset()`, `.value` getter - `DecayOptions`, `DecayFunction`, `Decay` (types) ### Scheduler module (`src/scheduler/`) - `createScheduler(opts?)` — returns a `Scheduler` with `.schedule(fn, delay)`, `.cancel(id)`, `.drain(signal?)`, `.dispose()` - `SchedulerOptions`, `SchedulerHandle`, `Scheduler` (types) ### Stopwatch module (`src/stopwatch/`) - `createStopwatch(opts?)` — returns a `Stopwatch` with `.start()`, `.stop()`, `.reset()`, `.lap()`, `.elapsed` getter, `.laps` getter - `StopwatchOptions`, `StopwatchLap`, `Stopwatch` (types) ### Throttle module (`src/throttle/`) - `throttle(fn, wait, opts?)` — leading/trailing edge configurable - `debounce(fn, wait, opts?)` — with `.flush()` and `.cancel()` methods on the returned function - `ThrottleOptions`, `DebounceOptions`, `ThrottledFunction`, `DebouncedFunction` (types) ### Timer module (`src/timer/`) - `createTimer(opts)` — interval-based with `.start()`, `.stop()`, `.reset()`, `.tick` event - `createCountdown(duration, opts?)` — countdown with `.start()`, `.pause()`, `.resume()`, `.stop()`, `.remaining` getter - `TimerOptions`, `CountdownOptions`, `Timer`, `Countdown` (types) ### Vector clock module (`src/vector-clock/`) - `createVectorClock(nodeId, opts?)` — returns a `VectorClock` with `.increment()`, `.update(remote)`, `.compare(other)`, `.toJSON()`, `.fromJSON(raw)` - `vectorClockCompare(a, b)` → `'before' | 'after' | 'concurrent' | 'equal'` - `VectorClockOptions`, `VectorClockState`, `VectorClock` (types) ## New additions for genesis ### Structured errors - `TimingError` extends `SuaveplanError` with codes under `TIMING.*` namespace - Codes: `TIMING.SCHEDULER.DISPOSED`, `TIMING.COUNTDOWN.INVALID_DURATION`, `TIMING.VECTOR_CLOCK.UNKNOWN_NODE` ### Zod schemas - `SchedulerOptionsSchema`, `StopwatchOptionsSchema`, `TimerOptionsSchema`, `CountdownOptionsSchema`, `VectorClockOptionsSchema` ### Injectable clock - All time-reading functions accept optional `{ clock?: Clock }` from `@suaveplan/types` - Scheduler and timer use injected clock for deterministic tests ### AbortSignal support - `Scheduler.drain(signal?)`, `Countdown` start/pause all honour `AbortSignal` ### OTel instrumentation - Histograms for stopwatch elapsed, scheduler queue depth; counters for timer ticks ### Property-based tests (fast-check) - Vector-clock ordering: transitivity, anti-symmetry - Throttle: output count ≤ ceil(events / wait) - Decay: monotonically decreasing (or increasing) toward target ### Benchmarks (mitata) - `throttle` 10 000 events at 16ms window - `createVectorClock` merge 1 000 nodes - `createScheduler` drain 1 000 tasks ## Impact - Adds one new package: `packages/universal/timing` - Adds one new spec capability: `timing` - No existing package consumers on genesis yet