Initial Commit
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,16 @@
|
||||
# Tasks: network-plugin-qos
|
||||
|
||||
- [x] 1. Write `openspec/changes/network-plugin-qos/proposal.md`
|
||||
- [x] 2. Write `openspec/changes/network-plugin-qos/tasks.md`
|
||||
- [x] 3. Scaffold `packages/network/network-plugin-qos/package.json`, `tsconfig.json`, `vitest.config.ts`
|
||||
- [x] 4. Implement `src/error-codes.ts` with `QOS_CODES`
|
||||
- [x] 5. Implement `src/enforcer/bandwidth-quota-enforcer.ts` — sliding window, quota checks
|
||||
- [x] 6. Implement `src/classifier/message-priority-classifier.ts` — type/size rules, QoSClass
|
||||
- [x] 7. Implement `src/router/qos-router.ts` — send logic, bypass/drop/queue/defer
|
||||
- [x] 8. Implement `src/monitor/congestion-monitor.ts` — alert thresholds, sustained period
|
||||
- [x] 9. Write `src/enforcer/enforcer.spec-conformance.test.ts`
|
||||
- [x] 10. Write `src/classifier/classifier.spec-conformance.test.ts`
|
||||
- [x] 11. Write `src/router/qos-router.spec-conformance.test.ts`
|
||||
- [x] 12. Write `src/monitor/congestion-monitor.spec-conformance.test.ts`
|
||||
- [x] 13. Write `tests/dep-graph.test.ts`
|
||||
- [x] 14. Run `bunx turbo lint typecheck test --filter=@suaveplan/network-plugin-qos` and achieve 100/100/100/100 coverage
|
||||
Reference in New Issue
Block a user