83 lines
4.3 KiB
Markdown
83 lines
4.3 KiB
Markdown
# Spec — network-discovery-hybrid
|
||
|
||
- **Capability**: `@suaveplan/network-discovery-hybrid`
|
||
- **Tier**: browser
|
||
- **Status**: SHIPPED 2026-05-11
|
||
- **Genesis path**: `packages/network/network-discovery-hybrid`
|
||
|
||
## ADDED Requirements
|
||
|
||
### Requirement 1 — Multi-Strategy Composition
|
||
|
||
The package SHALL ship a `HybridDiscoveryManager` that composes any subset of the five Wave-2 sibling discovery strategies (peerjs / crdt / trystero / webtorrent / gundb) plus arbitrary caller-supplied strategies behind a single `DiscoveryStrategy` contract from `@suaveplan/network-bootstrap`.
|
||
|
||
#### Scenario 1: Composite Discovery
|
||
|
||
- **WHEN** a `HybridDiscoveryManager` is configured with two strategies and `start()` + `discover(timeoutMs)` is called
|
||
- **THEN** the manager fans `discover()` out across every active strategy and returns the merged + deduplicated peer set.
|
||
|
||
### Requirement 2 — Priority-Based Strategy Selection
|
||
|
||
The orchestrator SHALL support a three-bucket strategy priority — `primary`, `fallback`, `backup` — and SHALL initialise strategies in priority order.
|
||
|
||
#### Scenario 1: Priority-Ordered Initialisation
|
||
|
||
- **WHEN** strategies are registered with mixed priorities
|
||
- **THEN** `initializeAll()` runs every primary first, then every fallback, then every backup.
|
||
|
||
### Requirement 3 — Per-Strategy Health Tracking
|
||
|
||
The orchestrator SHALL maintain a `StrategyHealth` record for every registered strategy with rolling success-rate (EMA, α = 0.3), consecutive-failure counter, last-error string, and active flag.
|
||
|
||
### Requirement 4 — Automatic Fallback
|
||
|
||
The orchestrator SHALL, when `autoFallback` is enabled and a primary becomes unavailable, initialise the next dormant non-primary strategy in priority order.
|
||
|
||
#### Scenario 1: Fallback Promotion
|
||
|
||
- **WHEN** a primary strategy reports `isAvailable() === false`
|
||
- **AND** at least one non-primary strategy is dormant
|
||
- **THEN** the orchestrator initialises the dormant strategy AND emits `hybrid:fallback{from,to}` AND increments `hybrid.fallback_total{from,to}`.
|
||
|
||
### Requirement 5 — Deduplicated Peer Set with PeerSource Provenance
|
||
|
||
The orchestrator SHALL maintain a deduplicated peer set keyed by `PeerInfo.peerId` with `PeerSource.discoveredBy` recording the ordered set of every strategy that has observed the peer.
|
||
|
||
#### Scenario 1: Append-Only Provenance
|
||
|
||
- **WHEN** the same peer is observed by two different strategies
|
||
- **THEN** the second observation appends to `discoveredBy` AND retains the original `primaryStrategy`.
|
||
|
||
### Requirement 6 — Optional Peer-Deps with Graceful Degradation
|
||
|
||
The package SHALL declare every sibling discovery strategy as `peerDependenciesMeta.<name>.optional: true`. A `StrategyConfig.factory` whose dynamic `import()` rejects SHALL be recorded as `STRATEGY_LOAD_FAILED` and the strategy MUST be marked unhealthy WITHOUT aborting `start()` for the remaining strategies.
|
||
|
||
### Requirement 7 — Lifecycle FSM
|
||
|
||
The orchestrator SHALL expose idempotent `start()`, `stop()`, and `dispose()` methods. After `dispose()` every method SHALL throw `NetDiscHybridError(DISPOSED)`.
|
||
|
||
### Requirement 8 — Error Registry
|
||
|
||
The package SHALL emit the six frozen codes `NO_STRATEGIES`, `ALL_STRATEGIES_DEGRADED`, `STRATEGY_LOAD_FAILED`, `DUPLICATE_STRATEGY`, `INVALID_OPTIONS`, `DISPOSED` via `defineCodes("NET_DISC_HYBRID", [...])` and surface them through `NetDiscHybridError extends SuaveplanError`.
|
||
|
||
### Requirement 9 — OpenTelemetry Instrumentation
|
||
|
||
The orchestrator SHALL emit the following instruments under tracer + meter name `@suaveplan/network-discovery-hybrid`:
|
||
|
||
- `hybrid.peer_sources_total{strategy}` counter
|
||
- `hybrid.strategy_health_score{strategy}` histogram
|
||
- `hybrid.fallback_total{from,to}` counter
|
||
- `hybrid.active_strategies{strategy}` up-down counter
|
||
- `hybrid.discover_duration_ms{outcome}` histogram
|
||
- `hybrid.start` and `hybrid.discover` spans
|
||
|
||
### Requirement 10 — Test-Time Real-Implementation Fixture
|
||
|
||
The package SHALL ship a real-implementation `TestStrategy` fixture under `tests/setup/test-strategy.ts` that fully implements the `DiscoveryStrategy` contract deterministically.
|
||
|
||
The package SHALL NOT contain any `vi.mock`, `jest.mock`, `__mocks__/` directory, or `: any` cast in production `src/` code.
|
||
|
||
### Requirement 11 — 100% Coverage
|
||
|
||
The package SHALL pass `bunx turbo test:coverage --filter=@suaveplan/network-discovery-hybrid` at 100% statements, branches, functions, and lines.
|