6.2 KiB
OpenSpec Change: enterprise-network-quality
- Change ID: enterprise-network-quality
- Package:
@suaveplan/network-quality - Category: universal/network
- Target path:
universal/network/network-quality - Status: SUPERSEDED-BY-GENESIS-WAVE
- Date: 2026-04-24
- Reference spec:
/mnt/s/web/suaveplan/enterprise/network-quality.md
Summary
Deliver @suaveplan/network-quality on the genesis branch from scratch at enterprise quality. The package provides network quality monitoring: continuous measurement of RTT, jitter, packet loss, and throughput; quality scoring with configurable thresholds; trend analysis (sliding window, exponential smoothing); degradation alerts; and a quality-aware selector for choosing the best peer/transport. Genesis adds structured errors via @suaveplan/error, Zod schemas for measurement and threshold types, OTel instrumentation on all quality metrics, AbortSignal on collection tasks, injectable Clock for measurement timestamps, event-bus emission for quality degradation and recovery, and property-based tests for scoring invariants.
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 NetworkQualityError; stable error codes |
@suaveplan/types (workspace:^) |
LoggerLike, Clock, EventBusLike |
@suaveplan/events (workspace:^) |
Event bus for quality change events |
@suaveplan/logger (workspace:^) |
Structured logging |
@suaveplan/timing (workspace:^) |
Stopwatch and interval timer for measurement |
zod (catalog:forms) |
Zod schemas |
@opentelemetry/api (catalog:observability) |
Deep OTel metric emission for network quality |
tslib (catalog:build) |
Runtime helpers |
Dev deps: vitest, @vitest/coverage-istanbul, fast-check (all catalog:testing).
Public API surface
Core
function createQualityMonitor(options?: QualityMonitorOptions): QualityMonitor
interface QualityMonitor {
readonly score: number
readonly grade: QualityGrade
start(signal?: AbortSignal): Promise<void>
stop(): void
measure(probe: QualityProbe): Promise<QualityMeasurement>
report(): QualityReport
on(event: QualityEvent, handler: (report: QualityReport) => void): () => void
}
Measurement types
interface QualityMeasurement {
readonly rttMs: number
readonly jitterMs: number
readonly packetLoss: number // 0–1
readonly throughputBps?: number
readonly timestamp: number
}
interface QualityReport {
readonly score: number // 0–100
readonly grade: QualityGrade
readonly current: QualityMeasurement
readonly trend: QualityTrend
readonly window: QualityWindowStats
readonly thresholdViolations: ReadonlyArray<ThresholdViolation>
}
interface QualityWindowStats {
readonly avgRttMs: number
readonly avgJitterMs: number
readonly avgPacketLoss: number
readonly p95RttMs: number
readonly sampleCount: number
readonly windowMs: number
}
type QualityTrend = 'improving' | 'stable' | 'degrading'
type QualityGrade = 'excellent' | 'good' | 'fair' | 'poor' | 'critical'
interface ThresholdViolation {
readonly metric: string
readonly threshold: number
readonly actual: number
readonly severity: 'warning' | 'critical'
}
Probe and selector
type QualityProbe = (signal?: AbortSignal) => Promise<QualityMeasurement>
function createRttProbe(url: string, options?: RttProbeOptions): QualityProbe
function createBandwidthProbe(url: string, options?: BandwidthProbeOptions): QualityProbe
function selectBestPeer<T extends { id: string; score?: number }>(
peers: T[],
monitor: QualityMonitor
): T | null
Options
interface QualityMonitorOptions {
measureIntervalMs?: number
windowSize?: number // number of samples in sliding window
smoothingFactor?: number // 0–1 for exponential smoothing
thresholds?: QualityThresholds
probe?: QualityProbe
logger?: LoggerLike
clock?: Clock
eventBus?: EventBusLike
}
interface QualityThresholds {
maxRttMs?: number
maxJitterMs?: number
maxPacketLoss?: number
minThroughputBps?: number
degradationScore?: number
criticalScore?: number
}
type QualityEvent = 'measurement' | 'degradation' | 'recovery' | 'critical'
Error codes
type NetworkQualityErrorCode =
| 'QUALITY_PROBE_FAILED'
| 'QUALITY_MONITOR_RUNNING'
| 'QUALITY_NO_MEASUREMENTS'
| 'QUALITY_ABORT'
function registerNetworkQualityErrorCodes(): void
Genesis additions
- Structured
NetworkQualityErrorwith stableQUALITY.*codes - Zod schemas for
QualityMonitorOptions,QualityThresholds - Exponential smoothing + sliding window statistics
- Trend detection — compares recent half of window against older half
- Quality scoring — weighted composite (RTT 40%, jitter 20%, packet loss 30%, throughput 10%)
createRttProbe/createBandwidthProbefactory utilities- OTel metric emission — gauges for
net.quality.rtt,net.quality.jitter,net.quality.packet_loss,net.quality.score - Property-based tests — score monotonically decreases as RTT increases; grade ordering matches score ordering
File layout
universal/network/network-quality/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/
index.ts
types/
common.ts
common.md
core/
monitor/
monitor.ts
monitor.md
monitor.types.ts
monitor.test.ts
index.ts
scoring/
scorer.ts
scorer.md
scorer.test.ts
index.ts
stats/
window-stats.ts
window-stats.md
window-stats.test.ts
index.ts
probes/
rtt-probe.ts
rtt-probe.md
rtt-probe.test.ts
bandwidth-probe.ts
bandwidth-probe.md
bandwidth-probe.test.ts
index.ts
__benchmarks__/
quality.bench.ts
tests/
integration.test.ts
property.test.ts
Impact
Workspace dep prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/logger, @suaveplan/timing must be published.