Initial Commit
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
<!-- markdownlint-disable MD024 -->
|
||||
|
||||
# Capability Spec Delta: network-plugin-monitor (complete-network-plugins)
|
||||
|
||||
**Package**: `@suaveplan/network-plugin-monitor`
|
||||
**Status**: PROPOSED
|
||||
|
||||
> Every requirement below carries a `**Verified by:**` line at authoring time.
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: MonitorPlugin conforms to NetworkPlugin lifecycle
|
||||
|
||||
The package SHALL export a `MonitorPlugin implements NetworkPlugin` and SHALL provide an integrated metric collector, alert engine, tracer, history store, and sampler on install.
|
||||
|
||||
#### Scenario: install / uninstall lifecycle
|
||||
|
||||
- **WHEN** a host installs then uninstalls the plugin
|
||||
- **THEN** the plugin reaches `INSTALLED` then `UNINSTALLED` and releases timers
|
||||
|
||||
**Verified by:** `src/plugin/monitor-plugin.spec-conformance.test.ts::"install / uninstall lifecycle is clean"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: MetricCollector supports the four metric types
|
||||
|
||||
The package SHALL export `MetricCollector`, `MetricCollectorConfig`, and `MetricDefinition`. The collector SHALL support Counter, Gauge, Histogram, and Summary metric types and SHALL throw `NetworkMonError(METRIC_NOT_FOUND)` / `METRIC_TYPE_MISMATCH` on misuse.
|
||||
|
||||
#### Scenario: unknown metric raises typed error
|
||||
|
||||
- **WHEN** `collector.record("not-registered", 1)` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.METRIC_NOT_FOUND"`
|
||||
|
||||
**Verified by:** `src/collector/metric-collector.spec-conformance.test.ts::"throws METRIC_NOT_FOUND on unknown metric"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: AlertEngine enforces unique rule ids
|
||||
|
||||
The package SHALL export `AlertEngine`, `AlertEngineConfig`, and `AlertBus`. Adding two rules with the same id SHALL throw `NetworkMonError(ALERT_RULE_DUPLICATE)`; operating on an unknown id SHALL throw `NetworkMonError(ALERT_RULE_NOT_FOUND)`.
|
||||
|
||||
#### Scenario: duplicate rule id
|
||||
|
||||
- **WHEN** `engine.addRule({ id: "x", … })` is called twice
|
||||
- **THEN** the second call throws `NetworkMonError(ALERT_RULE_DUPLICATE)`
|
||||
|
||||
**Verified by:** `src/alert/alert-engine.spec-conformance.test.ts::"throws ALERT_RULE_DUPLICATE on repeat id"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: GrafanaDashboardGenerator validates row titles with typed error
|
||||
|
||||
The package SHALL export `GrafanaDashboardGenerator`, `GrafanaDashboardOptions`, `GrafanaDashboardOptionsSchema`, `DashboardJson`, `GrafanaPanelType`, `GridPos`, and `GridPosSchema`. `addRow(title)` SHALL throw `NetworkMonError(DASHBOARD_ROW_INVALID)` when `title` is empty or whitespace-only. The class SHALL NOT throw bare `Error`.
|
||||
|
||||
#### Scenario: empty title raises typed error
|
||||
|
||||
- **WHEN** `generator.addRow("")` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.DASHBOARD_ROW_INVALID"` and `context.field === "title"`
|
||||
|
||||
**Verified by:** `src/grafana/dashboard-generator.spec-conformance.test.ts::"throws DASHBOARD_ROW_INVALID on empty title"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: BandwidthMonitor validates sample config with typed error
|
||||
|
||||
The package SHALL export `BandwidthMonitor` (in the `quality` module). The monitor SHALL throw `NetworkMonError(BANDWIDTH_MONITOR_CONFIG_INVALID)` whenever `maxSamples` is less than 1 or `smoothingFactor` is outside `(0, 1]`. The class SHALL NOT throw bare `RangeError`.
|
||||
|
||||
#### Scenario: invalid maxSamples
|
||||
|
||||
- **WHEN** `new BandwidthMonitor({ maxSamples: 0 })` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.BANDWIDTH_MONITOR_CONFIG_INVALID"` and `context.field === "maxSamples"`
|
||||
|
||||
#### Scenario: invalid smoothingFactor
|
||||
|
||||
- **WHEN** `new BandwidthMonitor({ smoothingFactor: 0 })` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.BANDWIDTH_MONITOR_CONFIG_INVALID"` and `context.field === "smoothingFactor"`
|
||||
|
||||
**Verified by:** `src/quality/bandwidth-monitor.spec-conformance.test.ts::"throws BANDWIDTH_MONITOR_CONFIG_INVALID on maxSamples < 1"` AND `src/quality/bandwidth-monitor.spec-conformance.test.ts::"throws BANDWIDTH_MONITOR_CONFIG_INVALID on smoothingFactor out of range"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: DegradationManager validates hysteresis and window config with typed error
|
||||
|
||||
The package SHALL export `DegradationManager` (in the `quality` module). The manager SHALL throw `NetworkMonError(DEGRADATION_CONFIG_INVALID)` whenever `hysteresisMs` is negative or `windowSize` is less than 1.
|
||||
|
||||
#### Scenario: negative hysteresisMs
|
||||
|
||||
- **WHEN** `new DegradationManager({ hysteresisMs: -1 })` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.DEGRADATION_CONFIG_INVALID"` and `context.field === "hysteresisMs"`
|
||||
|
||||
#### Scenario: zero windowSize
|
||||
|
||||
- **WHEN** `new DegradationManager({ windowSize: 0 })` is called
|
||||
- **THEN** the call throws `NetworkMonError` with `code === "NET_MON.DEGRADATION_CONFIG_INVALID"` and `context.field === "windowSize"`
|
||||
|
||||
**Verified by:** `src/quality/degradation-manager.spec-conformance.test.ts::"throws DEGRADATION_CONFIG_INVALID on negative hysteresisMs"` AND `src/quality/degradation-manager.spec-conformance.test.ts::"throws DEGRADATION_CONFIG_INVALID on zero windowSize"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: NetworkTracer propagates span context across mesh hops
|
||||
|
||||
The package SHALL export a tracer compatible with `@opentelemetry/api`. Operating on a closed span SHALL throw `NetworkMonError(SPAN_NOT_OPEN)`.
|
||||
|
||||
#### Scenario: closed span raises typed error
|
||||
|
||||
- **WHEN** `tracer.addEvent(closedSpanId, …)` is called
|
||||
- **THEN** the call throws `NetworkMonError(SPAN_NOT_OPEN)`
|
||||
|
||||
**Verified by:** `src/tracer/network-tracer.spec-conformance.test.ts::"throws SPAN_NOT_OPEN on closed span"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: HistoricalDataStore enforces retention with typed error
|
||||
|
||||
The package SHALL export a historical store and an adaptive sampler. Invalid retention SHALL throw `NetworkMonError(RETENTION_INVALID)`.
|
||||
|
||||
#### Scenario: invalid retention raises typed error
|
||||
|
||||
- **WHEN** `new HistoricalDataStore({ retentionMs: -1 })` is called
|
||||
- **THEN** the call throws `NetworkMonError(RETENTION_INVALID)`
|
||||
|
||||
**Verified by:** `src/history/historical-data-store.spec-conformance.test.ts::"throws RETENTION_INVALID on negative retention"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: Error-code registry is frozen and namespaced NET_MON
|
||||
|
||||
`NETWORK_MON_CODES` SHALL be frozen under the `NET_MON` namespace and SHALL include at minimum: `METRIC_NOT_FOUND`, `METRIC_TYPE_MISMATCH`, `ALERT_RULE_DUPLICATE`, `ALERT_RULE_NOT_FOUND`, `SPAN_NOT_OPEN`, `RETENTION_INVALID`, and the new `DASHBOARD_ROW_INVALID`, `BANDWIDTH_MONITOR_CONFIG_INVALID`, `DEGRADATION_CONFIG_INVALID`.
|
||||
|
||||
#### Scenario: registry contains the three new codes
|
||||
|
||||
- **WHEN** `NETWORK_MON_CODES` is inspected
|
||||
- **THEN** the three new codes map to their `"NET_MON.<KEY>"` values
|
||||
|
||||
**Verified by:** `src/error-codes.spec-conformance.test.ts::"NETWORK_MON_CODES includes DASHBOARD_ROW_INVALID, BANDWIDTH_MONITOR_CONFIG_INVALID, DEGRADATION_CONFIG_INVALID"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: No bare-Error throws in production code
|
||||
|
||||
`src/` SHALL contain zero bare `throw new (Error|TypeError|RangeError|SyntaxError)\(` sites outside test files.
|
||||
|
||||
#### Scenario: source grep returns zero hits
|
||||
|
||||
- **WHEN** the grep is run
|
||||
- **THEN** the output is empty
|
||||
|
||||
**Verified by:** `tests/no-bare-throws.test.ts::"network-plugin-monitor src/ has no bare Error throws"`
|
||||
|
||||
---
|
||||
|
||||
### Requirement: README is auto-docs idempotent
|
||||
|
||||
The package `README.md` SHALL contain exactly one balanced auto-docs block; the generator SHALL produce a byte-identical file on a second run.
|
||||
|
||||
#### Scenario: marker count is exactly one
|
||||
|
||||
- **WHEN** `grep -c "begin:auto-docs" packages/network/network-plugin-monitor/README.md`
|
||||
- **THEN** output is `1`
|
||||
|
||||
**Verified by:** `scripts/generate-package-module-tree.test.ts::"README regen is idempotent for network-plugin-monitor"`
|
||||
Reference in New Issue
Block a user