Three fixes for the SubscriptionManager/MxAccessClient subscription pipeline:
1. Serialize Subscribe and UnsubscribeClient with a SemaphoreSlim gate to prevent
race where old-session unsubscribe removes new-session COM subscriptions.
CreateMxAccessSubscriptionsAsync is now awaited instead of fire-and-forget.
2. Fix dual VTQ delivery in MxAccessClient.OnDataChange — each update was delivered
twice (once via stored callback, once via OnTagValueChanged property). Now uses
stored callback as the single delivery path.
3. Store pending tag addresses when CreateMxAccessSubscriptionsAsync fails (MxAccess
down) and retry them on reconnect via NotifyReconnection/RetryPendingSubscriptionsAsync.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replaced STA dispatch thread with Task.Run pattern for COM interop
- Fixed TypedValue oneof tracking with property-level _setCase field
- Added x-api-key DelegatingHandler for gRPC metadata authentication
- Fixed CheckApiKey RPC to validate request body key (not header)
- Integration tests: 15/17 pass (reads, subscribes, API keys, connections)
- 2 write tests pending (OnWriteComplete callback timing issue)
- v2 service deployed on windev port 50100
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>