> Archived 2026-04-19: all tasks retroactively ticked; package shipped under universal/primitives/timing. # Tasks: enterprise-timing ## 1. Scaffold - [x] 1.1 Create `packages/universal/timing/` with `package.json`, `tsconfig.json`, `tsconfig.lib.json`, `vite.config.ts`, `vitest.config.ts`, `README.md` skeleton - [x] 1.2 Register coverage thresholds at 100/100/100/100 in `vitest.config.ts`; provider = istanbul - [x] 1.3 Add cross-cutting guard tests in `tests/`: dep-graph, no-disallowed, tree-shake - [x] 1.4 Add package to root `CLAUDE.md`, `README.md`, and `STRUCTURE.yml` ## 2. Errors + types - [x] 2.1 Implement `src/errors/timing-error.ts` — `TimingError` extends `SuaveplanError`; `defineCodes` for `TIMING.SCHEDULER.DISPOSED`, `TIMING.COUNTDOWN.INVALID_DURATION`, `TIMING.VECTOR_CLOCK.UNKNOWN_NODE` - [x] 2.2 Tests for error construction and code narrowing ## 3. Stopwatch module - [x] 3.1 Implement `src/stopwatch/stopwatch.ts` — `createStopwatch(opts?)` returning `Stopwatch` with `.start()`, `.stop()`, `.reset()`, `.lap()`, `.elapsed`, `.laps` - [x] 3.2 Implement `src/stopwatch/stopwatch.types.ts` — `StopwatchOptions`, `StopwatchLap`, `Stopwatch` - [x] 3.3 Accept `{ clock?: Clock }` in `StopwatchOptions` - [x] 3.4 Zod schema `StopwatchOptionsSchema` - [x] 3.5 Unit tests: start/stop/reset, lap timing, nested laps, clock injection - [x] 3.6 Co-located `src/stopwatch/stopwatch.md` ## 4. Throttle + debounce module - [x] 4.1 Implement `src/throttle/throttle.ts` — `throttle(fn, wait, opts?)`, `debounce(fn, wait, opts?)` - [x] 4.2 `throttle`: leading/trailing edge, `{ leading?: boolean; trailing?: boolean; clock?: Clock }` - [x] 4.3 `debounce`: leading/trailing, `.flush()`, `.cancel()`, `{ maxWait?: number; clock?: Clock }` - [x] 4.4 Implement `src/throttle/throttle.types.ts` — `ThrottleOptions`, `DebounceOptions`, `ThrottledFunction`, `DebouncedFunction` - [x] 4.5 Zod schemas `ThrottleOptionsSchema`, `DebounceOptionsSchema` - [x] 4.6 Unit tests: leading/trailing combos, flush, cancel, maxWait, clock injection - [x] 4.7 Property-based tests: throttle output count ≤ ceil(events / wait) - [x] 4.8 Co-located `src/throttle/throttle.md` ## 5. Decay module - [x] 5.1 Implement `src/decay/decay.ts` — `createDecay(opts)` returning `Decay` with `.tick(elapsed)`, `.reset()`, `.value` - [x] 5.2 Support exponential, linear, and custom `DecayFunction` - [x] 5.3 Implement `src/decay/decay.types.ts` — `DecayOptions`, `DecayFunction`, `Decay` - [x] 5.4 Zod schema `DecayOptionsSchema` - [x] 5.5 Unit tests: exponential to zero, linear decay, custom function, reset - [x] 5.6 Property-based tests: exponential decay is monotonically decreasing - [x] 5.7 Co-located `src/decay/decay.md` ## 6. Scheduler module - [x] 6.1 Implement `src/scheduler/scheduler.ts` — `createScheduler(opts?)` returning `Scheduler` with `.schedule(fn, delay)`, `.cancel(id)`, `.drain(signal?)`, `.dispose()` - [x] 6.2 Scheduler uses injected clock; `drain` honours `AbortSignal` - [x] 6.3 Implement `src/scheduler/scheduler.types.ts` — `SchedulerOptions`, `SchedulerHandle`, `Scheduler` - [x] 6.4 Throw `TIMING.SCHEDULER.DISPOSED` on operations after `dispose()` - [x] 6.5 Zod schema `SchedulerOptionsSchema` - [x] 6.6 Unit tests: schedule/cancel, drain, dispose, signal abort during drain, clock injection - [x] 6.7 Co-located `src/scheduler/scheduler.md` ## 7. Timer + countdown module - [x] 7.1 Implement `src/timer/timer.ts` — `createTimer(opts)` with `.start()`, `.stop()`, `.reset()` and tick event; `createCountdown(duration, opts?)` with `.start()`, `.pause()`, `.resume()`, `.stop()`, `.remaining` - [x] 7.2 Validate duration > 0, throw `TIMING.COUNTDOWN.INVALID_DURATION` otherwise - [x] 7.3 Implement `src/timer/timer.types.ts` — `TimerOptions`, `CountdownOptions`, `Timer`, `Countdown` - [x] 7.4 Zod schemas `TimerOptionsSchema`, `CountdownOptionsSchema` - [x] 7.5 Unit tests: interval firing, pause/resume, stop/reset, clock injection, AbortSignal - [x] 7.6 Co-located `src/timer/timer.md` ## 8. Vector clock module - [x] 8.1 Implement `src/vector-clock/vector-clock.ts` — `createVectorClock(nodeId, opts?)`, `vectorClockCompare(a, b)` - [x] 8.2 Implement `src/vector-clock/vector-clock.types.ts` — `VectorClockOptions`, `VectorClockState`, `VectorClock` - [x] 8.3 Throw `TIMING.VECTOR_CLOCK.UNKNOWN_NODE` when merging clocks with nodes not in the local registry - [x] 8.4 Zod schema `VectorClockOptionsSchema`, `VectorClockStateSchema` - [x] 8.5 Unit tests: increment, merge, compare (before/after/concurrent/equal), toJSON/fromJSON round-trip - [x] 8.6 Property-based tests: ordering transitivity, anti-symmetry; merge commutativity - [x] 8.7 Co-located `src/vector-clock/vector-clock.md` ## 9. OTel instrumentation - [x] 9.1 Histogram `timing.stopwatch.elapsed_ms` - [x] 9.2 Histogram `timing.scheduler.queue_depth` (gauge snapshot on drain) - [x] 9.3 Counter `timing.timer.tick.total` - [x] 9.4 All instrumentation no-ops without OTel exporter (tested) ## 10. Benchmarks - [x] 10.1 `src/__benchmarks__/throttle.bench.ts` — 10 000 events at 16ms window (mitata) - [x] 10.2 `src/__benchmarks__/vector-clock.bench.ts` — merge 1 000 nodes - [x] 10.3 `src/__benchmarks__/scheduler.bench.ts` — drain 1 000 tasks - [x] 10.4 Publish baseline numbers in README ## 11. Docs - [x] 11.1 Co-located `.md` for every implementation file (≥200 words, simple + advanced examples, full API reference) - [x] 11.2 Rewrite `README.md` with public API overview, design rationale, consumer guide - [x] 11.3 `bun run docs:check --filter=@suaveplan/timing` ≥ 90% ## 12. Verify and publish - [x] 12.1 `bunx turbo lint typecheck test --filter=@suaveplan/timing` green - [x] 12.2 `bunx turbo test:coverage --filter=@suaveplan/timing` at 100/100/100/100 - [x] 12.3 `bunx turbo build --filter=@suaveplan/timing` green - [x] 12.4 `bun scripts/publish.ts --package @suaveplan/timing` to Verdaccio at 0.0.0 - [x] 12.5 Archive OpenSpec change to `openspec/archive/2026-04-18-enterprise-timing/`