4.7 KiB
OpenSpec Change: enterprise-network-assignment
- Change ID: enterprise-network-assignment
- Package:
@suaveplan/network-assignment - Category: universal/network
- Target path:
universal/network/network-assignment - Status: SUPERSEDED-BY-GENESIS-WAVE
- Date: 2026-04-24
Summary
Deliver @suaveplan/network-assignment on the genesis branch from scratch at enterprise quality. The package provides peer assignment algorithms: consistent hashing for deterministic peer selection, rendezvous hashing for load balancing, weighted random assignment, geographic/latency-aware assignment, and re-assignment on peer addition/removal with minimal disruption. Genesis adds structured errors via @suaveplan/error, Zod schemas for all assignment types, OTel instrumentation on assignment operations, injectable Rng for reproducible assignments, and property-based tests for distribution invariants.
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 NetworkAssignmentError; stable error codes |
@suaveplan/types (workspace:^) |
LoggerLike, Clock, Rng |
@suaveplan/logger (workspace:^) |
Structured logging |
zod (catalog:forms) |
Zod schemas |
@opentelemetry/api (catalog:observability) |
Spans + counters on assignment |
tslib (catalog:build) |
Runtime helpers |
Dev deps: vitest, @vitest/coverage-istanbul, fast-check (all catalog:testing).
Public API surface
Core
function createAssigner(options?: AssignerOptions): Assigner
interface Assigner {
addPeer(peer: Peer): void
removePeer(peerId: string): void
assign(key: string): Peer | null
assignN(key: string, n: number): ReadonlyArray<Peer>
rebalance(): RebalanceResult
snapshot(): AssignerSnapshot
}
Types
interface Peer {
id: string
weight?: number
region?: string
latencyMs?: number
capacity?: number
tags?: Record<string, string>
}
interface RebalanceResult {
readonly reassigned: number
readonly moved: ReadonlyArray<{ key: string; from: string; to: string }>
readonly durationMs: number
}
interface AssignerSnapshot {
readonly peers: ReadonlyArray<Peer>
readonly assignments: number
readonly algorithm: AssignmentAlgorithm
}
type AssignmentAlgorithm = 'consistent-hash' | 'rendezvous' | 'weighted-random' | 'latency-aware'
interface AssignerOptions {
algorithm?: AssignmentAlgorithm
virtualNodes?: number // for consistent hashing, default 150
replicationFactor?: number
rng?: Rng
logger?: LoggerLike
clock?: Clock
}
Algorithm utilities
function consistentHash(key: string, peers: Peer[], virtualNodes?: number): Peer | null
function rendezvousHash(key: string, peers: Peer[]): Peer | null
function weightedRandom(peers: Peer[], rng: Rng): Peer | null
function latencyAware(peers: Peer[], maxPeers?: number): Peer | null
Error codes
type NetworkAssignmentErrorCode =
| 'ASSIGN_NO_PEERS'
| 'ASSIGN_PEER_NOT_FOUND'
| 'ASSIGN_INVALID_OPTIONS'
function registerNetworkAssignmentErrorCodes(): void
Genesis additions
- Structured
NetworkAssignmentErrorwith stableASSIGN.*codes - Zod schemas for
AssignerOptions,Peer - Four assignment algorithms: consistent hash (FNV-1a + virtual nodes), rendezvous hash (HRW), weighted random, latency-aware
- Injectable
Rngfor deterministic weighted-random assignments in tests - OTel instrumentation — counter
assignment.assign_total, histogramassignment.rebalance_duration_ms - Property-based tests — consistent hash monotonicity (adding peer reassigns minimum keys), distribution uniformity, weight-proportional assignment
File layout
universal/network/network-assignment/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/
index.ts
types/
common.ts
common.md
core/
assigner/
assigner.ts
assigner.md
assigner.types.ts
assigner.test.ts
index.ts
algorithms/
consistent-hash.ts
consistent-hash.md
consistent-hash.test.ts
rendezvous-hash.ts
rendezvous-hash.md
rendezvous-hash.test.ts
weighted-random.ts
weighted-random.md
weighted-random.test.ts
latency-aware.ts
latency-aware.md
latency-aware.test.ts
__benchmarks__/
assignment.bench.ts
tests/
integration.test.ts
property.test.ts
Impact
Workspace dep prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/logger must be published.