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 ofnetwork-plugin-*andnetwork-*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.
- Structured-error non-conformance (HIGH). Eleven concrete
throw new Error(...),throw new RangeError(...)sites across five plugins bypass the per-packageSuaveplanErrorsubclass. This loses programmatic-handling (error.code), OTel span-event tagging, redaction, i18n message keys, and downstreaminstanceofassertions. The audit named five sites; verification (grep -rnE "throw new (Error|TypeError|RangeError|SyntaxError)\(") found six additional unflagged sites innetwork-plugin-intra-relayandnetwork-plugin-monitorthat ship in the same fix. - Missing canonical capability specs (MED). Five plugins (
auth,circuit-breaker,migration,partition,qos) have no archived OpenSpec change and noopenspec/specs/network-plugin-<name>/spec.md. Spot-check confirms the other five HIGH plugins ALSO have no canonical spec — every archivednetwork-plugin-*change went straight toproposal.md/tasks.mdwithout a## ADDED Requirementsdelta. This change authors specs for all ten as the baseline future deltas will be applied against. - README auto-docs regeneration bug (LOW).
scripts/generate-package-module-tree.tsreplaces 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.mdhas 22begin:auto-docsmarkers; 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")becomesthrow 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— boththrow new Error(...)(L57, L68) becomeNetworkTopoErrorwith new codeINVALID_LATENCY_CONFIG. - MODIFIED:
packages/network/network-plugin-state/src/bloom/bloom-filter-comparator.ts—throw new Error("bloom: byte length mismatch")becomesNetworkStateErrorwith new codeBLOOM_LENGTH_MISMATCH. - MODIFIED:
packages/network/network-plugin-intra-relay/src/monitor/relay-performance-monitor.ts—throw new Error(...)(L51) becomesNetworkIntraRelayErrorwith new codeHYSTERESIS_CONFIG_INVALID. - MODIFIED:
packages/network/network-plugin-intra-relay/src/security/relay-security-manager.ts— boththrow new RangeError(...)(L57, L62) becomeNetworkIntraRelayErrorwith new codeRATE_LIMIT_CONFIG_INVALID(audit-cited onlyrelay-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")becomesNetworkMonErrorwith new codeDASHBOARD_ROW_INVALID. - MODIFIED:
packages/network/network-plugin-monitor/src/quality/bandwidth-monitor.ts— boththrow new RangeError(...)(L49, L53) becomeNetworkMonErrorwith new codeBANDWIDTH_MONITOR_CONFIG_INVALID(newly found). - MODIFIED:
packages/network/network-plugin-monitor/src/quality/degradation-manager.ts— boththrow new RangeError(...)(L50, L54) becomeNetworkMonErrorwith new codeDEGRADATION_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 existingDESERIALIZATION_FAILED. - ADDED: new
*.spec-conformance.test.tsassertions on each migrated throw — pininstanceof NetworkXxxError,error.code === "NET_XXX.YYY", and stablecontextkeys.
Part B — author canonical capability specs (10 plugins)
- ADDED:
openspec/changes/complete-network-plugins/specs/network-plugin-<name>/spec.mdfor all ten plugins. Each delta is a## ADDED Requirementsblock 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 intoopenspec/specs/network-plugin-<name>/spec.md. - ADDED: every requirement carries a
**Verified by:**line pointing at either an existingsrc/<feature>/<feature>.spec-conformance.test.tsor 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.tshas a matching.mdand 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.mdand the 42 other malformedpackages/network/*/README.mdfiles — strip nested<!-- begin:auto-docs --> … <!-- end:auto-docs -->blocks (regex matching balanced outermost pairs, repeated to a fixpoint) before re-runningbun scripts/generate-package-module-tree.ts. - MODIFIED:
scripts/generate-package-module-tree.ts—replaceMarkedSectionis 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.mdMUST return exactly1for every file.
Out of scope
- Protocol-level redesigns — the binary wire format in
network-plugin-protocol(164-byte header, version negotiation), the gossip envelope innetwork-plugin-intra-relay, and the bloom-filter parameters innetwork-plugin-stateare unchanged. - New transports — no new
network-transport-*packages, no edits to existing transports beyond whatnetwork-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 futurenetwork-observability-*change. - Cross-mesh trust-store persistence —
network-plugin-authcurrently 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.tsalready gates this on every commit; if anynetwork-plugin-*test still imports fromvitestdirectly 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.tsassertion —expect(() => fn()).toThrowError(NetworkXxxError)AND.toMatchObject({ code: "NET_XXX.YYY", context: { … } }). The existingsrc/error-codes.spec-conformance.test.tsfor each plugin is extended to pin the new code constants in the frozen registry. - Part B:
bunx openspec validate complete-network-plugins --strictconfirms 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)"; doneMUST return zero lines. A test inscripts/generate-package-module-tree.test.tspins 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
codecheck shown above; bothe.message(still the same i18n key) ande.codeare 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 fromSuaveplanError)@suaveplan/network-testing— [x] tests run / [ ] docs reviewed / [ ] no action needed (fixture helpers may catch the migrated throws; assertions updated toinstanceof 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.