# OpenSpec Change: enterprise-browser-network-discovery-hybrid - **Change ID**: enterprise-browser-network-discovery-hybrid - **Package**: `@suaveplan/network-discovery-hybrid` - **Category**: browser - **Target path**: `browser/network/network-discovery-hybrid` - **Status**: SUPERSEDED-BY-GENESIS-WAVE - **Date**: 2026-04-24 - **Reference spec**: `/mnt/s/web/suaveplan/enterprise/network-discovery-hybrid.md` --- ## Summary Deliver `@suaveplan/network-discovery-hybrid` on the genesis branch at enterprise quality. The package composes any subset of the sibling discovery strategies into a single `HybridDiscoveryManager` with priority-based peer selection, health tracking per strategy, automatic fallback, and de-duplicated peer sets. No `__mocks__/` directory, no `vi.stubGlobal`, no `any` — tests exercise real `DiscoveryStrategy` implementations from sibling packages installed as devDependencies. --- ## Current-state audit (genesis) Fresh build — does not exist on genesis yet. --- ## Available workspace deps on genesis | Package | Role | |---|---| | `@suaveplan/network` (`workspace:^`) | `DiscoveryStrategy` interface | | `@suaveplan/error` (`workspace:^`) | Typed hybrid errors | | `@suaveplan/types` (`workspace:^`) | `LoggerLike` | | `@suaveplan/schema-registry` (`workspace:^`) | Config schema registration | | `zod` (`catalog:forms`) | `HybridDiscoveryConfig` schema | | `@opentelemetry/api` (`catalog:observability`) | Strategy health metrics | | `tslib` (`catalog:build`) | Runtime helpers | Optional peer deps (devDependencies for tests): `@suaveplan/network-discovery-peerjs`, `@suaveplan/network-discovery-trystero`, `@suaveplan/network-discovery-webtorrent`, `@suaveplan/network-discovery-crdt`, `@suaveplan/network-discovery-gundb`. Dev: `vitest`, `@vitest/coverage-istanbul`, `@suaveplan/testing`. React in devDeps for story. --- ## Preserved public API surface (from main branch) ```ts class HybridDiscoveryManager { constructor(config: HybridDiscoveryConfig) start(): Promise stop(): Promise getPeers(): PeerInfo[] getStrategyHealth(): Record addStrategy(config: StrategyConfig): void removeStrategy(id: string): void on(event: HybridDiscoveryEvent, handler: Function): void static presets: { browserP2P(): HybridDiscoveryConfig } } interface HybridDiscoveryConfig { strategies: StrategyConfig[] fallbackOrder?: string[] deduplicatePeers?: boolean } interface StrategyConfig { id: string; strategy: DiscoveryStrategy; priority: StrategyPriority; enabled?: boolean } interface StrategyHealth { status: 'healthy' | 'degraded' | 'failed'; peersDiscovered: number; lastError?: Error } type StrategyPriority = 'high' | 'medium' | 'low' | number type HybridDiscoveryEvent = 'peer:discovered' | 'peer:left' | 'strategy:health:change' | 'strategy:failover' | 'error' // + PeerSource, HybridManagerStatus ``` --- ## New additions for genesis ### 1. No `__mocks__/` — real implementations Tests install sibling discovery packages as `devDependencies` and instantiate real `DiscoveryStrategy` objects. A minimal in-tree `MemoryDiscoveryStrategy` (implements the real interface, not duck-typed) is provided for unit tests. ### 2. `HybridDiscoveryConfig` Zod schema Full config validation; registered in `@suaveplan/schema-registry`. ### 3. Typed `StrategyLoadError` When a peer-dep strategy is missing, `strategy-loader.ts` returns a typed `STRATEGY_LOAD_FAILED` error — never fails silently. ### 4. Deterministic priority tie-breaking Equal-priority strategies are ranked alphabetically by `id`. ### 5. Back-pressure Configurable `maxPeerEventsPerSecond` per strategy; excess events queued or dropped with counter metric. ### 6. `HybridDiscoveryManager.presets.browserP2P()` One-liner wiring PeerJS + Trystero with sensible defaults. ### 7. Error codes `STRATEGY_LOAD_FAILED`, `STRATEGY_UNAVAILABLE`, `HYBRID_NO_HEALTHY_STRATEGY`. ### 8. OTel metrics Counter `discovery.hybrid.strategy_healthy`, counter `discovery.hybrid.strategy_degraded`, counter `discovery.hybrid.strategy_failed`; histogram `discovery.hybrid.failover_ms`. --- ## File layout ```text browser/network/network-discovery-hybrid/ package.json tsconfig.json vitest.config.ts src/ index.ts error-codes.ts hybrid-discovery-manager/ hybrid-discovery-manager.ts hybrid-discovery-manager.md hybrid-discovery-manager.types.ts hybrid-discovery-manager.test.ts index.ts strategy-manager/ strategy-manager.ts strategy-manager.md strategy-manager.test.ts index.ts strategy-loader/ strategy-loader.ts strategy-loader.md strategy-loader.test.ts index.ts lifecycle/ lifecycle.ts lifecycle.md lifecycle.test.ts index.ts peer-tracker/ peer-tracker.ts peer-tracker.md peer-tracker.test.ts index.ts presets/ presets.ts presets.md index.ts internal/ memory-discovery-strategy.ts (test double implementing real interface) tests/ config.test.ts config-advanced.test.ts runtime.test.ts (split ≤500 lines) runtime-failover.test.ts ``` --- ## Impact **Downstream**: top-level P2P networking clients. **Prerequisites**: `@suaveplan/network`, `@suaveplan/error` on Verdaccio; sibling discovery packages as devDeps.