# Capability Spec Delta: network-plugin-protocol (complete-network-plugins) **Package**: `@suaveplan/network-plugin-protocol` **Status**: PROPOSED > Every requirement below carries a `**Verified by:**` line at authoring time. ## ADDED Requirements ### Requirement: BinaryProtocol header carries version and routing metadata The package SHALL export a `BinaryProtocol` class together with the constants `PROTOCOL_VERSION` and `HEADER_SIZE` defining the fixed-width header used on the wire. Headers SHALL be opaque to consumers and addressed only through the encoder / decoder pair. #### Scenario: header round-trips through encoder / decoder - **WHEN** a `MessageEnvelope` is encoded with `MessageEncoder` and decoded with `MessageDecoder` - **THEN** the round-trip produces a structurally-equal envelope and the decoded header carries the same `PROTOCOL_VERSION` constant **Verified by:** `src/protocol/protocol.spec-conformance.test.ts::"BinaryProtocol round-trips an envelope"` --- ### Requirement: MessageDecoder throws structured errors on malformed input `MessageDecoder` SHALL throw `NetworkProtoError` (subclass of `SuaveplanError`) with `code === "NET_PROTO.DESERIALIZATION_FAILED"` and a `context` payload identifying the failure cause whenever the input buffer is too short, the header is invalid, or deserialization fails. The package SHALL NOT throw bare `Error` / `TypeError` / `RangeError` from any production code path. #### Scenario: incomplete buffer raises typed error - **WHEN** `MessageDecoder.decode` is called with a buffer whose length is less than `HEADER_SIZE` - **THEN** the call throws `NetworkProtoError` with `code === "NET_PROTO.DESERIALIZATION_FAILED"` and `context.reason === "incomplete-message"` **Verified by:** `src/decoder/decoder.spec-conformance.test.ts::"throws NetworkProtoError on incomplete buffer"` --- ### Requirement: ProtocolPipeline composes ordered stages with backpressure The package SHALL export `ProtocolPipeline` with a `PipelineStage` interface that consumers register in order. The pipeline SHALL invoke stages in registration order on encode and in reverse on decode. #### Scenario: stages run in registration order on encode and reverse on decode - **WHEN** stages `A`, `B` are registered in that order and a message flows through encode-then-decode - **THEN** the observed call sequence is `A.encode`, `B.encode`, `B.decode`, `A.decode` **Verified by:** `src/pipeline/pipeline.spec-conformance.test.ts::"runs stages in declared order"` --- ### Requirement: PriorityMessageQueue rejects overflow with QUEUE_FULL The package SHALL export `PriorityMessageQueue` and `MessageBatcher`. The queue SHALL throw `NetworkProtoError(QUEUE_FULL)` when an insert would exceed the configured capacity. #### Scenario: insert beyond capacity raises QUEUE_FULL - **WHEN** the queue holds `capacity` messages and a further `enqueue` is attempted - **THEN** the call throws `NetworkProtoError` with `code === "NET_PROTO.QUEUE_FULL"` **Verified by:** `src/queue/queue.spec-conformance.test.ts::"throws QUEUE_FULL on overflow"` --- ### Requirement: ProtocolPlugin conforms to NetworkPlugin lifecycle The package SHALL export `ProtocolPlugin implements NetworkPlugin` and a `ProtocolPluginOptions` type. The plugin SHALL register itself against the host on `install`, register pluggable serializers via the options object, and tear down state on `uninstall`. #### Scenario: install registers the plugin and exposes encoder/decoder via the host - **WHEN** a host calls `await plugin.install(host)` followed by `await plugin.uninstall(host)` - **THEN** the plugin enters `INSTALLED` then `UNINSTALLED` lifecycle states and does not leak resources **Verified by:** `src/protocol/protocol-plugin.spec-conformance.test.ts::"install / uninstall lifecycle is clean"` --- ### Requirement: Error-code registry is frozen and namespaced NET_PROTO `NETWORK_PROTO_CODES` SHALL be a frozen registry under the `NET_PROTO` namespace exporting at minimum: `INVALID_HEADER`, `PAYLOAD_TOO_LARGE`, `SERIALIZATION_FAILED`, `DESERIALIZATION_FAILED`, `UNSUPPORTED_SERIALIZER`, `QUEUE_FULL`, `TTL_EXPIRED`, `LOOP_DETECTED`, `DUPLICATE_MESSAGE`. Every code SHALL be reachable from at least one production throw site. #### Scenario: registry membership - **WHEN** `NETWORK_PROTO_CODES` is inspected - **THEN** every key maps to a value of the form `"NET_PROTO."` **Verified by:** `src/error-codes.spec-conformance.test.ts::"NETWORK_PROTO_CODES is frozen and prefixed NET_PROTO"` --- ### Requirement: No bare-Error throws in production code The package SHALL NOT contain any `throw new Error(...)`, `throw new TypeError(...)`, `throw new RangeError(...)`, or `throw new SyntaxError(...)` statement inside `src/` (excluding `*.test.ts` and `*.spec-conformance.test.ts`). Every production failure path SHALL throw `NetworkProtoError` (or a `SuaveplanError` subclass from a transitive dependency). #### Scenario: source grep returns zero hits - **WHEN** `grep -rnE "throw new (Error|TypeError|RangeError|SyntaxError)\(" packages/network/network-plugin-protocol/src/ --include="*.ts"` is run, excluding `*.test.ts` - **THEN** the output is empty **Verified by:** `tests/no-bare-throws.test.ts::"network-plugin-protocol src/ has no bare Error throws"` --- ### Requirement: README is auto-docs idempotent The package `README.md` SHALL contain exactly one balanced ` … ` block. Re-running `bun scripts/generate-package-module-tree.ts` SHALL produce a byte-identical file. #### Scenario: marker count is exactly one - **WHEN** `grep -c "begin:auto-docs" packages/network/network-plugin-protocol/README.md` is run - **THEN** the output is `1` **Verified by:** `scripts/generate-package-module-tree.test.ts::"README regen is idempotent for network-plugin-protocol"`