12 commits since 0.3.3:
- refactor(api): typed StreamEvent variants with symbol+interval keys
- refactor(api): drop redundant symbol from Ticker/PublicTrade/MarkPrice/
FundingRate/OpenInterest/OrderUpdateEvent/PositionUpdateEvent payloads
- refactor(api): Order.symbol → Option<String>
- refactor(api): KlineInterval newtype across Stream/Kind/Event/StreamEvent
- refactor(api): MarketWarning.symbol → Option<String>
- refactor(api): OrderUpdate / PositionUpdate become struct variants
- fix(station): Event.symbol is per-handle (echoes user-input format)
- fix(station): event_matches_key uniform — OB cross-pollination closed
- fix(bitstamp): extract OB symbol from channel name
- fix(gateio): parse_kline correctly extracts interval AND symbol from `n`
- fix(klines): emit interval on Polygon/CryptoCompare/Alpaca Kline events
- fix(normalization): propagate symbol+interval into CanonicalEvent
- fix(dydx): validate signing key length explicitly (closes baseline test)
Tests: 830/0 core, 75/0 station, +6 ignored live integration tests
(dual_symbol_routing, label_per_subscriber). Strict check clean.
Live smoke verified on Binance + GateIO.