Files
suaveplan/openspec/archive/2026-05-12-enterprise-network-standby-transport/proposal.md
2026-05-27 23:29:53 +01:00

5.2 KiB
Raw Blame History

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

  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

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.