Extracts ~200 lines of duplicated WebSocket lifecycle code into shared abstract base class.
- Template method pattern: base owns lifecycle, subclasses override hooks
- ProcessMessageAsync always async (Task.CompletedTask for sync gateway)
- Private _webSocket, subclasses use SendRawAsync only
- 20 new base class tests, 596 total pass
- 399 lines removed, net ~170 less production code
Closes#63
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>