# Capability Spec Delta: network-plugin-state (complete-network-plugins) **Package**: `@suaveplan/network-plugin-state` **Status**: PROPOSED > Every requirement below carries a `**Verified by:**` line at authoring time. ## ADDED Requirements ### Requirement: StatePlugin conforms to NetworkPlugin lifecycle The package SHALL export `StatePlugin implements NetworkPlugin` and `StatePluginConfig`. The plugin SHALL manage state synchronization, delta compression, history pruning, and reconciliation against peer states. #### Scenario: install / uninstall lifecycle - **WHEN** a host installs then uninstalls the plugin - **THEN** the plugin reaches `INSTALLED` then `UNINSTALLED` cleanly **Verified by:** `src/plugin/state-plugin.spec-conformance.test.ts::"install / uninstall lifecycle is clean"` --- ### Requirement: BloomFilter and BloomFilterComparator detect divergence The package SHALL export `BloomFilter`, `BloomFilterComparator`, and `BloomFilterConfig`. The comparator SHALL diff two bit-vectors of equal byte-length and return the set of suspected divergent slots. #### Scenario: comparator finds divergent slots - **WHEN** two filters of the same configuration are compared - **THEN** the result identifies slots set in one and unset in the other **Verified by:** `src/bloom/bloom-filter-comparator.spec-conformance.test.ts::"diff identifies divergent slots"` --- ### Requirement: BloomFilterComparator rejects length-mismatch with typed error `BloomFilterComparator` SHALL throw `NetworkStateError` with `code === "NET_STATE.BLOOM_LENGTH_MISMATCH"` and a `context` payload carrying both byte lengths whenever the two filters' byte arrays have different sizes. The class SHALL NOT throw bare `Error`. #### Scenario: byte-length mismatch - **WHEN** two bloom filters of byte lengths 8 and 16 are compared - **THEN** the call throws `NetworkStateError` with `code === "NET_STATE.BLOOM_LENGTH_MISMATCH"` and `context === { left: 8, right: 16 }` **Verified by:** `src/bloom/bloom-filter-comparator.spec-conformance.test.ts::"throws BLOOM_LENGTH_MISMATCH on byte-length mismatch"` --- ### Requirement: DeltaCompressor produces and applies state diffs The package SHALL export `DeltaCompressor` that takes prior and next state snapshots and produces a compact delta that, when applied to the prior, reconstructs the next. #### Scenario: delta round-trip reconstructs next state - **WHEN** `apply(prev, compress(prev, next))` is computed - **THEN** the result is structurally equal to `next` **Verified by:** `src/delta/delta-compressor.spec-conformance.test.ts::"compress / apply round-trip"` --- ### Requirement: Reconciler deepMerge merges peer-state branches The package SHALL export `deepMerge` and a reconciler abstraction that merges two state branches under a configurable strategy. Missing strategy keys SHALL raise `NetworkStateError(STRATEGY_MISSING_MERGE)`. #### Scenario: missing strategy raises typed error - **WHEN** a reconciler is run with no strategy registered for the key in conflict - **THEN** the call throws `NetworkStateError` with `code === "NET_STATE.STRATEGY_MISSING_MERGE"` **Verified by:** `src/reconciler/reconciler.spec-conformance.test.ts::"throws STRATEGY_MISSING_MERGE when no strategy registered"` --- ### Requirement: StateHistoryPruner enforces retention policy The package SHALL export `StateHistoryPruner` and `StateHistoryPrunerConfig`. The pruner SHALL drop history entries older than the configured retention window and SHALL raise `NetworkStateError(PRUNE_INVALID_RETENTION)` on invalid retention configuration. #### Scenario: invalid retention raises typed error - **WHEN** `new StateHistoryPruner({ retentionMs: -1 })` is called - **THEN** the call throws `NetworkStateError` with `code === "NET_STATE.PRUNE_INVALID_RETENTION"` **Verified by:** `src/pruner/state-history-pruner.spec-conformance.test.ts::"throws PRUNE_INVALID_RETENTION on negative window"` --- ### Requirement: Error-code registry is frozen and namespaced NET_STATE `NETWORK_STATE_CODES` SHALL be frozen under the `NET_STATE` namespace and SHALL include at minimum: `PATH_INVALID`, `STRATEGY_MISSING_MERGE`, `DELTA_OUT_OF_ORDER`, `RESOURCE_PROFILE_UNKNOWN`, `PRUNE_INVALID_RETENTION`, and the new `BLOOM_LENGTH_MISMATCH`. #### Scenario: registry contains BLOOM_LENGTH_MISMATCH - **WHEN** `NETWORK_STATE_CODES` is inspected - **THEN** `BLOOM_LENGTH_MISMATCH` maps to `"NET_STATE.BLOOM_LENGTH_MISMATCH"` **Verified by:** `src/error-codes.spec-conformance.test.ts::"NETWORK_STATE_CODES includes BLOOM_LENGTH_MISMATCH"` --- ### Requirement: No bare-Error throws in production code `src/` SHALL contain zero bare `throw new (Error|TypeError|RangeError|SyntaxError)\(` sites outside test files. #### Scenario: source grep returns zero hits - **WHEN** `grep -rnE "throw new (Error|TypeError|RangeError|SyntaxError)\(" packages/network/network-plugin-state/src/ --include="*.ts"` excluding tests - **THEN** the output is empty **Verified by:** `tests/no-bare-throws.test.ts::"network-plugin-state 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-state/README.md` - **THEN** output is `1` **Verified by:** `scripts/generate-package-module-tree.test.ts::"README regen is idempotent for network-plugin-state"`