Files
suaveplan/openspec/changes/complete-network-plugins/specs/network-plugin-topology/spec.md
2026-05-27 23:29:53 +01:00

4.8 KiB

Capability Spec Delta: network-plugin-topology (complete-network-plugins)

Package: @suaveplan/network-plugin-topology Status: PROPOSED

Every requirement below carries a **Verified by:** line at authoring time.

ADDED Requirements

Requirement: TopologyPlugin conforms to NetworkPlugin lifecycle

The package SHALL export TopologyPlugin implements NetworkPlugin and TopologyPluginConfig. The plugin SHALL manage peer-tier assignment and group membership on install, and tear down assigners and buses on uninstall.

Scenario: install / uninstall lifecycle

  • WHEN a host calls install then uninstall
  • THEN the plugin reaches INSTALLED then UNINSTALLED and releases all timers

Verified by: src/plugin/topology-plugin.spec-conformance.test.ts::"install / uninstall lifecycle is clean"


Requirement: LatencyAssigner buckets peers by measured latency

The package SHALL export LatencyAssigner, LatencyAssignerConfig, LatencyBucket, and LatencyBus. The assigner SHALL bucket peers into named latency tiers based on a configurable bucket schedule and SHALL emit bucket-change events on the LatencyBus.

Scenario: peer moves between buckets on RTT change

  • WHEN a peer's measured RTT crosses a bucket boundary
  • THEN the assigner emits a bucket-change event on the bus with the old and new bucket

Verified by: src/latency/latency-assigner.spec-conformance.test.ts::"emits bucket-change when RTT crosses boundary"


Requirement: LatencyAssigner validates config with typed errors

LatencyAssigner SHALL validate its config at construction time and throw NetworkTopoError with code === "NET_TOPO.INVALID_LATENCY_CONFIG" whenever the bucket schedule is empty, non-monotonic, or contains a non-finite boundary. The class SHALL NOT throw bare Error.

Scenario: empty bucket schedule

  • WHEN new LatencyAssigner({ buckets: [] }) is called
  • THEN the call throws NetworkTopoError with code === "NET_TOPO.INVALID_LATENCY_CONFIG" and context.reason === "empty-buckets"

Scenario: non-monotonic bucket boundaries

  • WHEN the bucket schedule is [100, 50, 200]
  • THEN the call throws NetworkTopoError with code === "NET_TOPO.INVALID_LATENCY_CONFIG" and context.reason === "non-monotonic"

Verified by: src/latency/latency-assigner.spec-conformance.test.ts::"throws INVALID_LATENCY_CONFIG on empty buckets" AND src/latency/latency-assigner.spec-conformance.test.ts::"throws INVALID_LATENCY_CONFIG on non-monotonic schedule"


Requirement: GroupManager exposes a typed group abstraction

The package SHALL export GroupManager, Group, GroupBus, and GroupManagerConfig. The manager SHALL track named groups of peers with add / remove operations and SHALL emit membership-change events on the GroupBus.

Scenario: add/remove emits membership events

  • WHEN groupManager.add(groupId, peerId) is called for a peer not yet in the group
  • THEN a member-added event fires on the bus with { groupId, peerId }

Verified by: src/group/group-manager.spec-conformance.test.ts::"emits member-added on join"


Requirement: Error-code registry is frozen and namespaced NET_TOPO

NETWORK_TOPO_CODES SHALL be frozen under the NET_TOPO namespace and SHALL include at minimum: INVALID_TIER, PEER_NOT_FOUND, ALREADY_AT_TIER, and the new INVALID_LATENCY_CONFIG. Every code SHALL be reachable from a production throw site.

Scenario: registry contains INVALID_LATENCY_CONFIG

  • WHEN NETWORK_TOPO_CODES is inspected
  • THEN INVALID_LATENCY_CONFIG maps to "NET_TOPO.INVALID_LATENCY_CONFIG"

Verified by: src/error-codes.spec-conformance.test.ts::"NETWORK_TOPO_CODES includes INVALID_LATENCY_CONFIG"


Requirement: No bare-Error throws in production code

The package SHALL NOT contain any throw new (Error|TypeError|RangeError|SyntaxError)\( site inside src/ outside test files. Every production failure throws NetworkTopoError or a transitive SuaveplanError subclass.

Scenario: source grep returns zero hits

  • WHEN grep -rnE "throw new (Error|TypeError|RangeError|SyntaxError)\(" packages/network/network-plugin-topology/src/ --include="*.ts" excluding tests
  • THEN the output is empty

Verified by: tests/no-bare-throws.test.ts::"network-plugin-topology 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-topology/README.md
  • THEN output is 1

Verified by: scripts/generate-package-module-tree.test.ts::"README regen is idempotent for network-plugin-topology"