Files
2026-05-27 23:29:53 +01:00

6.4 KiB
Raw Permalink Blame History

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.

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.

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.

class QoSRouter {
  constructor(options: {
    classifier: MessagePriorityClassifier;
    enforcer: BandwidthQuotaEnforcer;
    transportManager: TransportManager; // from network-plugin-transport-manager
  });
  send(envelope: MessageEnvelope, targetPeerId: string): Promise<void>;
}

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.

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

const QOS_CODES = defineCodes("QOS", [
  "QUOTA_EXCEEDED",
  "RELAY_QUOTA_EXCEEDED",
  "MESSAGE_DROPPED",
  "CONGESTION_ALERT",
  "INVALID_QOS_CLASS",
] as const);

QosError extends SuaveplanError<QosErrorCode>.


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.