Files
suaveplan/openspec/archive/2026-05-12-enterprise-network-quality/proposal.md
2026-05-27 23:29:53 +01:00

6.2 KiB
Raw Blame History

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

  1. Structured NetworkQualityError with stable QUALITY.* codes
  2. Zod schemas for QualityMonitorOptions, QualityThresholds
  3. Exponential smoothing + sliding window statistics
  4. Trend detection — compares recent half of window against older half
  5. Quality scoring — weighted composite (RTT 40%, jitter 20%, packet loss 30%, throughput 10%)
  6. createRttProbe / createBandwidthProbe factory utilities
  7. OTel metric emission — gauges for net.quality.rtt, net.quality.jitter, net.quality.packet_loss, net.quality.score
  8. 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.