5.6 KiB
OpenSpec Change: enterprise-network-registry
- Change ID: enterprise-network-registry
- Package:
@suaveplan/network-registry - Category: universal/network
- Target path:
universal/network/network-registry - Status: SUPERSEDED-BY-GENESIS-WAVE
- Date: 2026-04-24
- Reference spec:
/mnt/s/web/suaveplan/enterprise/network-registry.md
Summary
Deliver @suaveplan/network-registry on the genesis branch from scratch at enterprise quality. The package provides a network service and peer registry: register/deregister services with metadata and capabilities, health-status tracking, TTL-based expiry, lookup by capability/tag/region, and change-notification subscriptions. Genesis adds structured errors via @suaveplan/error, Zod schemas for all registry types, OTel instrumentation on register/lookup operations, AbortSignal on async lookup, injectable Clock for TTL expiry, event-bus emission for registration changes, and property-based tests for lookup correctness.
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 NetworkRegistryError; stable error codes |
@suaveplan/types (workspace:^) |
LoggerLike, Clock, EventBusLike |
@suaveplan/events (workspace:^) |
Event bus for registration changes |
@suaveplan/logger (workspace:^) |
Structured logging |
zod (catalog:forms) |
Zod schemas |
@opentelemetry/api (catalog:observability) |
Spans + counters on register/lookup |
tslib (catalog:build) |
Runtime helpers |
Dev deps: vitest, @vitest/coverage-istanbul, fast-check (all catalog:testing).
Public API surface
Core
function createNetworkRegistry(options?: NetworkRegistryOptions): NetworkRegistry
interface NetworkRegistry {
register(entry: RegistryEntry): RegistrationHandle
deregister(entryId: string): boolean
lookup(query: RegistryQuery): ReadonlyArray<RegistryEntry>
get(entryId: string): RegistryEntry | null
list(filter?: RegistryFilter): ReadonlyArray<RegistryEntry>
updateHealth(entryId: string, status: HealthStatus): boolean
subscribe(query: RegistryQuery, handler: RegistryChangeHandler): () => void
purgeExpired(): number
}
Entry types
interface RegistryEntry {
id: string
name: string
type: 'peer' | 'service' | 'relay' | 'bootstrap'
address?: string
port?: number
region?: string
capabilities: string[]
tags?: Record<string, string>
metadata?: Record<string, unknown>
ttlMs?: number
registeredAt?: number
expiresAt?: number
health?: HealthStatus
}
interface HealthStatus {
healthy: boolean
lastCheckedAt: number
latencyMs?: number
load?: number // 0–1
}
interface RegistrationHandle {
readonly entryId: string
renew(ttlMs?: number): void
deregister(): void
}
Query types
interface RegistryQuery {
type?: RegistryEntry['type'] | Array<RegistryEntry['type']>
capabilities?: string[] // entry must have ALL listed capabilities
anyCapabilities?: string[] // entry must have AT LEAST ONE
tags?: Record<string, string> // all tag key/value pairs must match
region?: string
healthyOnly?: boolean
limit?: number
}
interface RegistryFilter {
type?: RegistryEntry['type'] | Array<RegistryEntry['type']>
healthyOnly?: boolean
region?: string
}
type RegistryChangeHandler = (change: RegistryChange) => void
interface RegistryChange {
type: 'registered' | 'deregistered' | 'health-changed' | 'expired'
entry: RegistryEntry
previous?: RegistryEntry
}
Options
interface NetworkRegistryOptions {
ttlDefaultMs?: number
maxEntries?: number
gcIntervalMs?: number
logger?: LoggerLike
clock?: Clock
eventBus?: EventBusLike
}
Error codes
type NetworkRegistryErrorCode =
| 'REGISTRY_ENTRY_NOT_FOUND'
| 'REGISTRY_DUPLICATE_ID'
| 'REGISTRY_CAPACITY_EXCEEDED'
| 'REGISTRY_INVALID_ENTRY'
| 'REGISTRY_EXPIRED'
function registerNetworkRegistryErrorCodes(): void
Genesis additions
- Structured
NetworkRegistryErrorwith stableREGISTRY.*codes - Zod schemas for
RegistryEntry,RegistryQuery,NetworkRegistryOptions - TTL-based expiry with periodic GC via injectable
Clock;purgeExpired()callable manually - Subscription-based change notifications with query-scoped filtering
- Capability AND/OR query operators —
capabilities(AND),anyCapabilities(OR) - Health status tracking with
updateHealth()API - OTel instrumentation — counter
registry.register_total,registry.deregister_total,registry.lookup_total, histogramregistry.lookup_results - Property-based tests — lookup(query) results are always a subset of
list(); TTL expiry correctness
File layout
universal/network/network-registry/
package.json
tsconfig.json
vitest.config.ts
src/
index.ts
error-codes.ts
constants/
index.ts
types/
common.ts
common.md
core/
registry/
registry.ts
registry.md
registry.types.ts
registry.test.ts
index.ts
query-engine/
query-engine.ts
query-engine.md
query-engine.test.ts
index.ts
ttl-manager/
ttl-manager.ts
ttl-manager.md
ttl-manager.test.ts
index.ts
tests/
integration.test.ts
property.test.ts
Impact
Workspace dep prerequisites: @suaveplan/error, @suaveplan/types, @suaveplan/events, @suaveplan/logger must be published.