Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,57 @@
# Capability Spec: Timing
**Package**: `@suaveplan/timing`
**Version**: 0.0.0 (genesis)
**Status**: ADDED
---
## ADDED Requirements
### TM-01 — Injectable clock
Every module that reads wall-clock time MUST accept `{ clock?: Clock }` from `@suaveplan/types`. No `Date.now()` or `setTimeout` at module scope. Default clock uses `Date.now()`.
### TM-02 — AbortSignal support
`Scheduler.drain(signal?)` and streaming/iterative helpers MUST honour `AbortSignal`. Abort resolves the operation cleanly without throwing unless the signal fires mid-operation, in which case an `AbortError`-compatible rejection is emitted.
### TM-03 — Stopwatch
`createStopwatch` MUST return a `Stopwatch` whose `.elapsed` is monotonically non-decreasing between `.start()` and `.stop()`. `.lap()` MUST record the split time relative to the previous lap start (or the stopwatch start). `.reset()` MUST clear all laps and reset elapsed to 0.
### TM-04 — Throttle / debounce
`throttle` MUST emit at most one invocation per `wait` window (leading or trailing edge, configurable). `debounce` MUST delay invocation until `wait` ms after the last call; `.flush()` MUST invoke immediately; `.cancel()` MUST suppress the pending invocation. `maxWait` option on `debounce` caps total delay.
### TM-05 — Decay
`createDecay` MUST accept a `DecayFunction` (or preset name `'exponential' | 'linear'`). `.tick(elapsed)` advances the decay by `elapsed` milliseconds. The returned `.value` MUST be bounded in `[target, initial]` (or `[initial, target]` for growth). `.reset()` MUST restore `initial`.
### TM-06 — Scheduler
`createScheduler` MUST execute scheduled callbacks at or after their requested delay using the injected clock. `.cancel(id)` MUST prevent the callback from firing. `.drain(signal?)` MUST flush all pending callbacks in delay order. After `.dispose()`, any operation MUST throw `TimingError` with code `TIMING.SCHEDULER.DISPOSED`.
### TM-07 — Timer and countdown
`createTimer` MUST fire its tick event at each `interval`. `createCountdown` MUST validate that `duration > 0`; otherwise throw `TimingError` with code `TIMING.COUNTDOWN.INVALID_DURATION`. `.pause()` / `.resume()` MUST preserve `.remaining` across pause/resume cycles.
### TM-08 — Vector clock
`createVectorClock` MUST maintain a `Map<nodeId, number>` counter. `.increment()` MUST increment the local node's counter. `.update(remote)` MUST take the component-wise maximum. `vectorClockCompare` MUST return `'before' | 'after' | 'concurrent' | 'equal'` correctly for all pairs. `.toJSON()` / `.fromJSON()` MUST produce a lossless round-trip.
### TM-09 — Structured errors
All thrown errors MUST extend `TimingError` which extends `SuaveplanError`. Codes under `TIMING.*` namespace.
### TM-10 — Zod schemas
Every public options type MUST have a corresponding Zod schema in a sibling `*.schemas.ts` file.
### TM-11 — OTel instrumentation
Stopwatch elapsed, scheduler queue depth, and timer tick counter MUST emit via `@opentelemetry/api`. All instruments are no-ops when no exporter is registered.
### TM-12 — sideEffects: false + coverage 100%
`"sideEffects": false` with tree-shake test. Vitest thresholds at 100/100/100/100. No `.skip` / `.only` in `src/`.