5.2 KiB
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
function createStandbyTransportPool(options: StandbyTransportPoolOptions): StandbyTransportPool
interface StandbyTransportPool {
readonly primary: Transport | null
readonly standby: ReadonlyArray<Transport>
readonly state: PoolState
add(transport: Transport): void
remove(transportId: string): void
send(message: unknown, signal?: AbortSignal): Promise<void>
promote(transportId: string): void
on(event: PoolEvent, handler: (data: PoolEventData) => void): () => void
}
Transport interface
interface Transport {
readonly id: string
readonly priority: number
readonly state: TransportState
readonly score: number // 0–100 quality score
send(message: unknown, signal?: AbortSignal): Promise<void>
connect(signal?: AbortSignal): Promise<void>
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
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
type StandbyTransportErrorCode =
| 'STANDBY_NO_TRANSPORT'
| 'STANDBY_SEND_FAILED'
| 'STANDBY_TRANSPORT_NOT_FOUND'
| 'STANDBY_ALL_FAILED'
| 'STANDBY_ABORT'
function registerStandbyTransportErrorCodes(): void
Genesis additions
- Structured
StandbyTransportErrorwith stableSTANDBY.*codes - Zod schemas for
StandbyTransportPoolOptions - Score-based promotion — promotion triggered when primary score drops below
degradationThreshold - Promotion debounce — uses
@suaveplan/timingthrottle to avoid promotion thrash - In-flight message re-routing — queued messages replayed on new primary after promotion
- Injectable
Clockfor promotion delay testing - OTel instrumentation — span
standby.promote, counterstandby.promotions_total, histogramstandby.promotion_delay_ms - Property-based tests — pool always has a primary when transports are available; promotion selects highest-scoring standby
File layout
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.