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

13 KiB

Complete network-plugin-* family hygiene

  • Change ID: complete-network-plugins
  • Packages: @suaveplan/network-plugin-protocol, @suaveplan/network-plugin-topology, @suaveplan/network-plugin-state, @suaveplan/network-plugin-intra-relay, @suaveplan/network-plugin-monitor, @suaveplan/network-plugin-auth, @suaveplan/network-plugin-circuit-breaker, @suaveplan/network-plugin-migration, @suaveplan/network-plugin-partition, @suaveplan/network-plugin-qos (cross-cutting fixes touch the rest of network-plugin-* and network-* README fleet)
  • Status: PROPOSED
  • Type: spec-conformance + bug-fix + new-spec (multi)
  • Date: 2026-05-17
  • Design: ./design.md
  • Spec deltas: ./specs//spec.md (10 files — one per plugin)

Why

A family-wide audit of packages/network/network-plugin-* surfaced three independent hygiene gaps that must be closed before any of the plugins can be declared enterprise-done. Per CLAUDE.md §3 ("Build feature-rich, production-grade packages") and the "no deferrals on migration" rule, all three problems ship in this single change rather than being split into follow-ups that would leave the family in a half-migrated state.

  1. Structured-error non-conformance (HIGH). Eleven concrete throw new Error(...), throw new RangeError(...) sites across five plugins bypass the per-package SuaveplanError subclass. This loses programmatic-handling (error.code), OTel span-event tagging, redaction, i18n message keys, and downstream instanceof assertions. The audit named five sites; verification (grep -rnE "throw new (Error|TypeError|RangeError|SyntaxError)\(") found six additional unflagged sites in network-plugin-intra-relay and network-plugin-monitor that ship in the same fix.
  2. Missing canonical capability specs (MED). Five plugins (auth, circuit-breaker, migration, partition, qos) have no archived OpenSpec change and no openspec/specs/network-plugin-<name>/spec.md. Spot-check confirms the other five HIGH plugins ALSO have no canonical spec — every archived network-plugin-* change went straight to proposal.md/tasks.md without a ## ADDED Requirements delta. This change authors specs for all ten as the baseline future deltas will be applied against.
  3. README auto-docs regeneration bug (LOW). scripts/generate-package-module-tree.ts replaces the section between <!-- begin:auto-docs --> / <!-- end:auto-docs --> markers, but when a previous run injected nested or unbalanced markers, the regex matches the outermost pair only, leaving every nested duplicate in place. network-plugin-auth/README.md has 22 begin:auto-docs markers; the worst offender (network-discovery-trystero/README.md) has 110. 43 network-package READMEs are malformed.

What changes

Part A — error-handling migration (5 HIGH plugins; 11 cited + 6 newly-found sites)

  • MODIFIED: packages/network/network-plugin-protocol/src/decoder/decoder.ts — throw new Error("protocol.incomplete-message") becomes throw new NetworkProtoError(NETWORK_PROTO_CODES.DESERIALIZATION_FAILED, "protocol.incomplete-message", { context: { reason: "incomplete-message", remaining } }).
  • MODIFIED: packages/network/network-plugin-topology/src/latency/latency-assigner.ts — both throw new Error(...) (L57, L68) become NetworkTopoError with new code INVALID_LATENCY_CONFIG.
  • MODIFIED: packages/network/network-plugin-state/src/bloom/bloom-filter-comparator.ts — throw new Error("bloom: byte length mismatch") becomes NetworkStateError with new code BLOOM_LENGTH_MISMATCH.
  • MODIFIED: packages/network/network-plugin-intra-relay/src/monitor/relay-performance-monitor.ts — throw new Error(...) (L51) becomes NetworkIntraRelayError with new code HYSTERESIS_CONFIG_INVALID.
  • MODIFIED: packages/network/network-plugin-intra-relay/src/security/relay-security-manager.ts — both throw new RangeError(...) (L57, L62) become NetworkIntraRelayError with new code RATE_LIMIT_CONFIG_INVALID (audit-cited only relay-performance-monitor.ts; this one was missed).
  • MODIFIED: packages/network/network-plugin-monitor/src/grafana/dashboard-generator.ts — throw new Error("addRow: title must be non-empty") becomes NetworkMonError with new code DASHBOARD_ROW_INVALID.
  • MODIFIED: packages/network/network-plugin-monitor/src/quality/bandwidth-monitor.ts — both throw new RangeError(...) (L49, L53) become NetworkMonError with new code BANDWIDTH_MONITOR_CONFIG_INVALID (newly found).
  • MODIFIED: packages/network/network-plugin-monitor/src/quality/degradation-manager.ts — both throw new RangeError(...) (L50, L54) become NetworkMonError with new code DEGRADATION_CONFIG_INVALID (newly found).
  • ADDED: per-plugin error codes — NETWORK_TOPO_CODES.INVALID_LATENCY_CONFIG, NETWORK_STATE_CODES.BLOOM_LENGTH_MISMATCH, NETWORK_INTRA_RELAY_CODES.{HYSTERESIS_CONFIG_INVALID, RATE_LIMIT_CONFIG_INVALID}, NETWORK_MON_CODES.{DASHBOARD_ROW_INVALID, BANDWIDTH_MONITOR_CONFIG_INVALID, DEGRADATION_CONFIG_INVALID}. No new code needed for the protocol case — reuses existing DESERIALIZATION_FAILED.
  • ADDED: new *.spec-conformance.test.ts assertions on each migrated throw — pin instanceof NetworkXxxError, error.code === "NET_XXX.YYY", and stable context keys.

Part B — author canonical capability specs (10 plugins)

  • ADDED: openspec/changes/complete-network-plugins/specs/network-plugin-<name>/spec.md for all ten plugins. Each delta is a ## ADDED Requirements block enumerating the full current public surface (classes, factories, lifecycle, error codes, OTel instruments where present, plugin-host contract) so that future changes have a baseline to delta against. On archive these fold into openspec/specs/network-plugin-<name>/spec.md.
  • ADDED: every requirement carries a **Verified by:** line pointing at either an existing src/<feature>/<feature>.spec-conformance.test.ts or a new test authored in this change (Part A creates several).
  • ADDED: parity-vs-intent notes for the five MED plugins are folded into the spec deltas — no separate "missing features" list because the audit found no under-shipped surface (every export in index.ts has a matching .md and a matching *.spec-conformance.test.ts; the gap was purely the missing canonical spec).

Part C — README regeneration fleet-wide

  • MODIFIED: packages/network/network-plugin-auth/README.md and the 42 other malformed packages/network/*/README.md files — strip nested <!-- begin:auto-docs --> … <!-- end:auto-docs --> blocks (regex matching balanced outermost pairs, repeated to a fixpoint) before re-running bun scripts/generate-package-module-tree.ts.
  • MODIFIED: scripts/generate-package-module-tree.ts — replaceMarkedSection is hardened to detect and collapse nested marker pairs before substitution (prevents recurrence). A regression test pins the round-trip: README → generate → generate again → byte-identical.
  • ADDED: pre-archive scan grep -c "begin:auto-docs" packages/network/*/README.md MUST return exactly 1 for every file.

Out of scope

  • Protocol-level redesigns — the binary wire format in network-plugin-protocol (164-byte header, version negotiation), the gossip envelope in network-plugin-intra-relay, and the bloom-filter parameters in network-plugin-state are unchanged.
  • New transports — no new network-transport-* packages, no edits to existing transports beyond what network-plugin-* consumers strictly require.
  • OTel instrumentation expansion — only the error-handling paths gain OTel span-event tagging (free with SuaveplanError); broader meter/histogram coverage is left for a future network-observability-* change.
  • Cross-mesh trust-store persistence — network-plugin-auth currently holds the trust set in-memory; persistent backing is a separate change.
  • Family-wide test-runner-import sweep — bun scripts/lint/check-test-runner-imports.ts already gates this on every commit; if any network-plugin-* test still imports from vitest directly the gate flags it, and we fix it inline during Part A.

Source mapping

This change is genesis-original (the per-plugin audits and the README bug were discovered on genesis, not in upstream enterprise/*.md). Where an upstream enterprise audit doc exists for a sibling concept (../suaveplan/enterprise/network-observability.md, ../suaveplan/enterprise/network-protocol.md) the new code names follow upstream conventions, but no clause is lifted verbatim.

Requirement Source Notes
Bare-error replacement (all sites) genesis grep evidence sites enumerated in §What changes
Per-plugin spec drafts current src/ of each plugin reverse-engineered from existing exports + *.spec-conformance.test.ts
README regeneration scripts/generate-package-module-tree.ts bug reproducer: run script twice, see marker count double

Requirements with no source line

Requirement Justification
New error codes (7 added across 4 plugins) The bare-Error sites have no existing matching code in the per-plugin registry; introducing codes is the structural fix, not a feature add
README idempotency regression test Prevents the same defect from re-landing once auto-docs is re-run

Verification approach

  • Part A: each migrated throw site gets a src/<feature>/<feature>.spec-conformance.test.ts assertion — expect(() => fn()).toThrowError(NetworkXxxError) AND .toMatchObject({ code: "NET_XXX.YYY", context: { … } }). The existing src/error-codes.spec-conformance.test.ts for each plugin is extended to pin the new code constants in the frozen registry.
  • Part B: bunx openspec validate complete-network-plugins --strict confirms every requirement has a **Verified by:** line referencing a real file path; bun scripts/openspec-conformance.ts @suaveplan/network-plugin-<pkg> confirms every cited test exists and matches the requirement.
  • Part C: post-fix scan for f in packages/network/*/README.md; do n=$(grep -c "begin:auto-docs" "$f"); [ "$n" -eq 1 ] || echo "BAD: $f ($n)"; done MUST return zero lines. A test in scripts/generate-package-module-tree.test.ts pins the double-run-idempotent invariant.

Migration

This change introduces 7 new error codes that consumers MAY assert on. None of the migrated throw sites was previously stable API (the bare Error.message strings were never documented as a contract), but downstream network-* packages that catch generically MAY now receive a SuaveplanError subclass where they previously received a plain Error.

  • Old behavior: catch (e) { if (e.message === "bloom: byte length mismatch") { … } }
  • New behavior: catch (e) { if (e instanceof NetworkStateError && e.code === "NET_STATE.BLOOM_LENGTH_MISMATCH") { … } }
  • Search command for consumers: grep -rln "bloom: byte length mismatch\|protocol.incomplete-message\|addRow: title must be non-empty\|hysteresisMs must be\|burstSize must be\|maxSamples must be\|smoothingFactor must be\|windowSize must be" packages/
  • Recommended replacement: switch to the typed code check shown above; both e.message (still the same i18n key) and e.code are stable now.

Impact

Affected dependents

Run bunx turbo ls --filter=...@suaveplan/network-plugin-{protocol,topology,state,intra-relay,monitor,auth,circuit-breaker,migration,partition,qos} to enumerate. Per-plugin dependents are the network composite packages and downstream consumers:

  • @suaveplan/network — [x] tests run / [x] docs reviewed / [ ] no action needed (consumes all 10 plugins via plugin registry; behavior-change is additive — new error codes inherit from SuaveplanError)
  • @suaveplan/network-testing — [x] tests run / [ ] docs reviewed / [ ] no action needed (fixture helpers may catch the migrated throws; assertions updated to instanceof NetworkXxxError)
  • @suaveplan/network-bootstrap — [ ] tests run / [x] docs reviewed / [x] no action needed (consumes the plugin registry but not the migrated throw sites)
  • @suaveplan/network-content-delivery, @suaveplan/network-intra-relay, @suaveplan/network-session, @suaveplan/network-webrtc — [ ] tests run / [x] docs reviewed / [x] no action needed (composite packages re-export plugin types; new error codes are purely additive)
  • @suaveplan/drive-network-integration — [ ] tests run / [x] docs reviewed / [x] no action needed (doesn't import any of the migrated modules directly)
  • All @suaveplan/network-transport-* — [ ] tests run / [x] docs reviewed / [x] no action needed (transports do not import plugin-level error classes)

Dependent-sweep proof — after Part A lands, run:

bunx turbo test --filter=...@suaveplan/network-plugin-protocol \
                --filter=...@suaveplan/network-plugin-topology \
                --filter=...@suaveplan/network-plugin-state \
                --filter=...@suaveplan/network-plugin-intra-relay \
                --filter=...@suaveplan/network-plugin-monitor

A green run is the §13 step 10 acceptance for the five HIGH plugins.