# OpenSpec Change: network-observability-consolidation - **Change ID**: network-observability-consolidation - **Affects**: - `@suaveplan/network-plugin-monitor` ✅ (shipped — extended) - `@suaveplan/network-observability` (upstream — folded in OR migrated as new plugin) - **Category**: universal - **Status**: PROPOSED (decision required at execution time) - **Date**: 2026-05-11 - **Parent**: `network-transport-family` (2026-05-11) — Wave 6 - **Migration source**: `../suaveplan/packages/universal/network-observability` + `../suaveplan/enterprise/network-observability.md` --- ## Summary Resolve the duplication between upstream `@suaveplan/network-observability` (application-monitoring observability layer for the mesh) and shipped `@suaveplan/network-plugin-monitor` ✅ (peer-quality + RTT/loss scorers + alert thresholds + OTel wiring across 12 modules). Both target the same problem space — network-tier telemetry. This proposal **does not write code**. It captures the decision and the resulting work. --- ## Decision required: fold vs. plugin ### Option A — Fold into `network-plugin-monitor` (recommended) The shipped plugin already covers peer-quality scoring, RTT/loss, alert thresholds, and OTel. Upstream `network-observability` adds application-monitoring abstractions (probably topology metrics, event aggregation, dashboard primitives) — fold those into the shipped plugin as additional feature modules. Pro: single canonical telemetry surface. Pro: no new package. Pro: consumers don't choose between two overlapping options. Con: `network-plugin-monitor` grows. Mitigation: keep feature modules in their own subdirs, each ≤300 LOC. ### Option B — Ship as separate `@suaveplan/network-plugin-observability` Two plugins compose: `monitor` handles peer-quality, `observability` handles application-monitoring abstractions. Pro: smaller plugins. Pro: tree-shake observability when not needed. Con: consumers must wire both. Con: feature-creep boundary becomes blurry. **Recommendation: A.** This proposal proceeds under A unless audit reveals upstream `network-observability` contains a fundamentally different abstraction (e.g. event-aggregation pipeline that doesn't fit the monitor plugin's per-peer model). --- ## Current-state audit (perform at execution time) Upstream coverage: 100%. Investigate what `network-observability` actually contains beyond what `network-plugin-monitor` ships: ```bash ls ../suaveplan/packages/universal/network-observability/src/ diff <(grep -rh "^export" ../suaveplan/packages/universal/network-observability/src/) \ <(grep -rh "^export" packages/network/network-plugin-monitor/src/) ``` Outcome of audit determines fold-or-split. --- ## Parity Checklist (FINAL — audit complete 2026-05-12) Decision: **Option A — fold into `@suaveplan/network-plugin-monitor`**. Audit revealed upstream `network-observability` contains exactly three feature modules — all of them are **output / export adapters** for an external metric collector, not a fundamentally different application-monitoring abstraction: | Capability | Upstream | Existing (`monitor`) | Verdict | |---|---|---|---| | Per-peer quality scoring | 🚫 not present | ✅ | already covered | | RTT / loss collectors | 🚫 not present | ✅ (`MetricCollector`, `NetworkMonitor`) | already covered | | Alert thresholds | 🚫 not present | ✅ (`AlertEngine`) | already covered | | OTel wiring (internal) | 🚫 not present | ✅ (`@opentelemetry/api` instruments across 12 modules) | already covered | | **Prometheus exposition (text format)** | ✅ via `prom-client` | 🚫 | ⬆️ **folded as `prometheus/` (rewritten universal-tier, hand-rolled emitter; no `prom-client` dep)** | | **Grafana dashboard JSON generator + presets** | ✅ | 🚫 | ⬆️ **folded as `grafana/` (pure data builder, injectable `Rng`)** | | OTel SDK exporter bridge | ✅ via external SDK | 🚫 (uses `@opentelemetry/api` directly per genesis convention) | ❌ **NOT folded** — redundant; genesis monitor already emits via `@opentelemetry/api` so external SDKs pick up metrics natively | | Application-monitoring abstractions | 🚫 not present in upstream src | n/a | n/a | | Event-aggregation pipeline | 🚫 not present in upstream src | n/a | n/a | | Topology metrics | 🚫 not present in upstream src | (handled by `network-plugin-topology` ✅) | n/a | **Why fold and not split:** the upstream "package" is 1159 LOC total, only ~600 LOC of which is portable (`prom-client` and external `@opentelemetry/sdk` are deliberately *not* universal-tier and would taint a sibling). After portability filtering, only the Prometheus text emitter (~150 LOC) and Grafana JSON builder (~370 LOC) survive — too small for a sibling plugin, and they consume the existing monitor's `MetricCollector.scrape()` output directly. Folding makes a single canonical telemetry surface. **Why the OTel SDK exporter is dropped, not folded:** the upstream `otel-exporter.ts` (293 LOC) is an adapter that wraps `prom-client` metrics into `@opentelemetry/sdk-metrics` observable instruments. Genesis's `network-plugin-monitor` already declares its instruments through `@opentelemetry/api`'s `MeterProvider` — any externally-registered OTel SDK (`@suaveplan/opentelemetry`'s `NoopSdk`/`SdkFactory`, or a user's `NodeSDK`) picks them up natively. The bridge is structurally redundant. --- ## Acceptance gate 1. Audit performed; Option A or B chosen with documented rationale. 2. Bare `@suaveplan/network-observability` row removed from `STATUS.md` (becomes either folded-into-monitor or shipped as `network-plugin-observability`). 3. `bunx turbo lint typecheck test --filter='@suaveplan/network-plugin-monitor'` (or new plugin) green. 4. `bunx turbo test:coverage` 100/100/100/100 on the resulting package(s). 5. `STATUS.md` updated; supersession table extended. --- ## Out of scope - Cross-process observability federation (separate `network-plugin-observability-otlp` if needed). - Custom dashboard rendering (UI tier).