# OpenSpec Change: enterprise-network-standby-transport - **Change ID**: enterprise-network-standby-transport - **Package**: `@suaveplan/network-standby-transport` - **Category**: universal/network - **Target path**: `universal/network/network-standby-transport` - **Status**: SUPERSEDED-BY-GENESIS-WAVE - **Date**: 2026-04-24 --- ## Summary Deliver `@suaveplan/network-standby-transport` on the genesis branch from scratch at enterprise quality. The package provides a standby/failover transport layer that maintains a pool of transport connections ranked by quality, promotes the best available transport when the primary degrades, and transparently re-routes in-flight messages without loss. Genesis adds structured errors via `@suaveplan/error`, Zod schemas for transport and pool configuration, OTel instrumentation on promotion events, `AbortSignal` on async operations, injectable `Clock` for promotion timers, event-bus integration for standby state changes, and property-based tests for promotion ordering. --- ## Current-state audit (genesis) The package does not exist on genesis yet — this is a fresh build. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/error` (`workspace:^`) | Base class for `StandbyTransportError`; stable error codes | | `@suaveplan/types` (`workspace:^`) | `LoggerLike`, `Clock`, `EventBusLike` | | `@suaveplan/events` (`workspace:^`) | Event bus for standby state changes | | `@suaveplan/logger` (`workspace:^`) | Structured logging | | `@suaveplan/retry` (`workspace:^`) | Retry on transport failures | | `zod` (`catalog:forms`) | Zod schemas | | `@opentelemetry/api` (`catalog:observability`) | Spans + counters on transport promotion | | `tslib` (`catalog:build`) | Runtime helpers | Dev deps: `vitest`, `@vitest/coverage-istanbul`, `fast-check` (all `catalog:testing`). --- ## Public API surface ### Core ```ts function createStandbyTransportPool(options: StandbyTransportPoolOptions): StandbyTransportPool interface StandbyTransportPool { readonly primary: Transport | null readonly standby: ReadonlyArray readonly state: PoolState add(transport: Transport): void remove(transportId: string): void send(message: unknown, signal?: AbortSignal): Promise promote(transportId: string): void on(event: PoolEvent, handler: (data: PoolEventData) => void): () => void } ``` ### Transport interface ```ts interface Transport { readonly id: string readonly priority: number readonly state: TransportState readonly score: number // 0–100 quality score send(message: unknown, signal?: AbortSignal): Promise connect(signal?: AbortSignal): Promise disconnect(): void on(event: TransportEvent, handler: (data: unknown) => void): () => void } type TransportState = 'disconnected' | 'connecting' | 'connected' | 'degraded' | 'failed' type TransportEvent = 'connect' | 'disconnect' | 'degrade' | 'recover' | 'score-change' type PoolState = 'healthy' | 'degraded' | 'standby-active' | 'no-transport' type PoolEvent = 'primary-promoted' | 'standby-promoted' | 'transport-failed' | 'state-change' interface PoolEventData { previousPrimary?: Transport newPrimary?: Transport reason?: string } ``` ### Options ```ts interface StandbyTransportPoolOptions { promotionThreshold?: number // min score to promote, default 30 degradationThreshold?: number // score below which primary is considered degraded, default 60 promotionDelayMs?: number // debounce window before promotion, default 1000 maxStandby?: number logger?: LoggerLike clock?: Clock eventBus?: EventBusLike } ``` ### Error codes ```ts type StandbyTransportErrorCode = | 'STANDBY_NO_TRANSPORT' | 'STANDBY_SEND_FAILED' | 'STANDBY_TRANSPORT_NOT_FOUND' | 'STANDBY_ALL_FAILED' | 'STANDBY_ABORT' function registerStandbyTransportErrorCodes(): void ``` --- ## Genesis additions 1. **Structured `StandbyTransportError`** with stable `STANDBY.*` codes 2. **Zod schemas** for `StandbyTransportPoolOptions` 3. **Score-based promotion** — promotion triggered when primary score drops below `degradationThreshold` 4. **Promotion debounce** — uses `@suaveplan/timing` throttle to avoid promotion thrash 5. **In-flight message re-routing** — queued messages replayed on new primary after promotion 6. **Injectable `Clock`** for promotion delay testing 7. **OTel instrumentation** — span `standby.promote`, counter `standby.promotions_total`, histogram `standby.promotion_delay_ms` 8. **Property-based tests** — pool always has a primary when transports are available; promotion selects highest-scoring standby --- ## File layout ```text universal/network/network-standby-transport/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts constants/ index.ts types/ common.ts common.md core/ pool/ pool.ts pool.md pool.types.ts pool.test.ts index.ts promoter/ promoter.ts promoter.md promoter.test.ts index.ts tests/ integration.test.ts property.test.ts ``` --- ## Impact **Workspace dep prerequisites**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/events`, `@suaveplan/logger`, `@suaveplan/retry` must be published.