# OpenSpec Change: network-plugin-qos - **Change ID**: network-plugin-qos - **Package**: `@suaveplan/network-plugin-qos` (new) - **Status**: PROPOSED - **Date**: 2026-05-01 --- ## Summary Implement bandwidth management and quality-of-service (QoS) controls for the mesh. `network-plugin-transport-manager` provides 5 priority tiers for message routing, but there is no per-mesh bandwidth quota enforcement, no control-plane message prioritization that bypasses normal queues, and no cross-mesh relay bandwidth throttling. This plugin adds the policy layer on top of the transport manager's mechanics. --- ## Why **Current state**: `network-plugin-webrtc` has `bufferedAmount` backpressure. `network-plugin-transport-manager` has 5 priority tiers. `@suaveplan/rate-limiter` exists as a standalone package but is not integrated into the mesh. **What's missing**: - Per-mesh bandwidth quota enforcement - Message priority classes (control vs data vs bulk) with quota-aware scheduling - QoS: urgent messages (election, failover) bypass normal queue when mesh is saturated - Cross-mesh relay bandwidth throttling (prevent Tier 0 host saturation) --- ## Core components ### 1. `BandwidthQuotaEnforcer` Tracks and enforces per-mesh and per-peer bandwidth quotas. ```ts class BandwidthQuotaEnforcer { constructor(options: { meshId: string; meshQuotaBps: number; // bytes per second for entire mesh peerQuotaBps: number; // bytes per second per peer relayQuotaBps: number; // bytes per second for cross-mesh relay windowMs: number; // default 1000 }); recordSend(bytes: number, isRelay: boolean): void; canSend(bytes: number, isRelay: boolean): boolean; getMeshUtilization(): number; // 0.0 – 1.0 getPeerUtilization(peerId: string): number; on(event: "quota:exceeded", handler: (scope: string) => void): void; } ``` Uses a sliding window (default 1 second). When quota is exceeded, sends are delayed or rejected based on message priority. ### 2. `MessagePriorityClassifier` Assigns a `QoSClass` to every message based on its type and payload size. ```ts enum QoSClass { CONTROL_PLANE = 0, // elections, failover, heartbeats — never dropped REALTIME = 1, // game state, audio — low latency, may drop RELIABLE = 2, // file transfers, chat — guaranteed delivery BULK = 3, // backups, logs — best effort SCAVENGER = 4, // prefetch, analytics — first to drop } class MessagePriorityClassifier { classify(envelope: MessageEnvelope): QoSClass; registerRule(type: string, qosClass: QoSClass): void; registerSizeRule(maxBytes: number, qosClass: QoSClass): void; } ``` Default rules: - `election:*`, `failover:*`, `heartbeat:*` → `CONTROL_PLANE` - `game:state`, `audio:*` → `REALTIME` - `chat:*`, `file:chunk` → `RELIABLE` - `backup:*`, `log:*` → `BULK` - `prefetch:*`, `analytics:*` → `SCAVENGER` ### 3. `QoSRouter` Integrates with `network-plugin-transport-manager` to apply QoS policy. ```ts class QoSRouter { constructor(options: { classifier: MessagePriorityClassifier; enforcer: BandwidthQuotaEnforcer; transportManager: TransportManager; // from network-plugin-transport-manager }); send(envelope: MessageEnvelope, targetPeerId: string): Promise; } ``` **Routing behaviour**: 1. Classify message → `QoSClass`. 2. If `CONTROL_PLANE` → bypass quota check, send immediately via highest-priority transport. 3. If mesh quota exceeded: - `REALTIME` → drop (application is notified). - `RELIABLE` → queue with timeout; retry when quota available. - `BULK` / `SCAVENGER` → drop or defer to off-peak window. 4. If relay quota exceeded: - Cross-mesh messages are throttled; `SCAVENGER` relay traffic is dropped first. ### 4. `CongestionMonitor` Monitors mesh congestion and emits alerts. ```ts class CongestionMonitor { constructor(options: { enforcer: BandwidthQuotaEnforcer; alertThreshold: number; // default 0.90 sustainedPeriodMs: number; // default 5000 }); start(): void; stop(): void; getCongestionLevel(): "none" | "mild" | "severe" | "critical"; } ``` Emits `qos:congestion` events on the `NetworkBus` with level and recommended actions (e.g. "pause prefetch", "reduce broadcast frequency"). --- ## Error codes ```ts const QOS_CODES = defineCodes("QOS", [ "QUOTA_EXCEEDED", "RELAY_QUOTA_EXCEEDED", "MESSAGE_DROPPED", "CONGESTION_ALERT", "INVALID_QOS_CLASS", ] as const); ``` `QosError extends SuaveplanError`. --- ## Dependencies - **Consumes**: `@suaveplan/network` (`NetworkNode`, `NetworkBus`, `MessageEnvelope`), `@suaveplan/network-plugin-transport-manager` (`TransportManager`, priority routing), `@suaveplan/network-plugin-relay` (cross-mesh relay paths), `@suaveplan/error`, `@suaveplan/types`, `@opentelemetry/api`. - **Blocked on**: `network-core` (shipped), `network-plugin-transport-manager`. --- ## Verification approach - `src/enforcer/enforcer.spec-conformance.test.ts` — pins sliding window, quota enforcement, utilization math. - `src/classifier/classifier.spec-conformance.test.ts` — pins default rules, custom rules, size-based rules. - `src/router/qos-router.spec-conformance.test.ts` — pins CONTROL_PLANE bypass, drop/queue/defer logic. - `src/monitor/congestion-monitor.spec-conformance.test.ts` — pins alert thresholds, sustained period, level calculation. - 100/100/100/100 Istanbul coverage. --- ## Conformance requirements (proposed) - `NET-91` — `BandwidthQuotaEnforcer` tracks per-mesh, per-peer, and per-relay bandwidth using a sliding window. - `NET-92` — `MessagePriorityClassifier` assigns `QoSClass` based on message type and size. - `NET-93` — `CONTROL_PLANE` messages bypass quota checks and are sent immediately. - `NET-94` — `REALTIME` messages are dropped when mesh quota is exceeded. - `NET-95` — `RELIABLE` messages are queued with timeout when mesh quota is exceeded. - `NET-96` — `BULK` and `SCAVENGER` messages are dropped or deferred when mesh quota is exceeded. - `NET-97` — Cross-mesh relay traffic is throttled independently; `SCAVENGER` relay traffic is dropped first. - `NET-98` — `CongestionMonitor` emits `qos:congestion` events when utilization exceeds `alertThreshold` for `sustainedPeriodMs`. --- ## Out of scope - **Deep packet inspection** → v2; v1 uses message type and size only. - **Per-application QoS** → v2; v1 is mesh-wide. - **Traffic shaping via token bucket** → `@suaveplan/rate-limiter` may be integrated in v2; v1 uses sliding windows.