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

180 lines
6.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<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.
```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<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.