Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -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"`