Summary
Desktop IM sends chat messages through a message.send Hub WebSocket frame, but the Hub WebSocket handler does not implement that frame type. The server only accepts auth as the first frame and typing after auth, so Desktop's IM send path is currently a no-op from the backend's perspective.
Evidence
app/desktop/src/hooks/useIMChat.ts sendMessage calls ws.send("message.send", { session_id, content }).
app/desktop/src/__tests__/useIMChat.test.ts asserts that sendMessage sends the same message.send frame, so this is an intentional client path.
hub-server/internal/handler/ws.go authenticates the first frame, then switches only on ws.TypeTyping; every other frame type goes to the ws unknown frame type branch.
hub-server/internal/ws/frame.go defines auth and typing, but does not define a message.send client frame.
docs/design/integration.md and docs/roadmaps/integration.md document client-to-server Hub WS messages as auth and typing, while REST already has message send APIs.
Impact
The Desktop IM composer can appear connected and call sendMessage, but the Hub will ignore the frame and no message.new event will be produced. Users can type into an apparently live Hub IM surface and silently fail to send messages.
Expected behavior
Pick one contract and align both sides:
- Prefer REST for message send: update Desktop IM to call the Hub REST send-message API, then rely on
message.new WS fanout for realtime delivery.
- Or deliberately add a Hub WS
message.send command, with the same auth, membership, idempotency, validation, and error semantics as REST.
Acceptance criteria
- Desktop IM send uses a backend-supported path.
- Unsupported WS frames either return a visible error frame or are not used by client code.
- Add an integration or hook test proving a Desktop send path reaches the Hub message service and produces or observes
message.new.
- Update Hub WS/client docs so client-to-server frame types match implementation.
Summary
Desktop IM sends chat messages through a
message.sendHub WebSocket frame, but the Hub WebSocket handler does not implement that frame type. The server only acceptsauthas the first frame andtypingafter auth, so Desktop's IM send path is currently a no-op from the backend's perspective.Evidence
app/desktop/src/hooks/useIMChat.tssendMessagecallsws.send("message.send", { session_id, content }).app/desktop/src/__tests__/useIMChat.test.tsasserts thatsendMessagesends the samemessage.sendframe, so this is an intentional client path.hub-server/internal/handler/ws.goauthenticates the first frame, then switches only onws.TypeTyping; every other frame type goes to thews unknown frame typebranch.hub-server/internal/ws/frame.godefinesauthandtyping, but does not define amessage.sendclient frame.docs/design/integration.mdanddocs/roadmaps/integration.mddocument client-to-server Hub WS messages asauthandtyping, while REST already has message send APIs.Impact
The Desktop IM composer can appear connected and call
sendMessage, but the Hub will ignore the frame and nomessage.newevent will be produced. Users can type into an apparently live Hub IM surface and silently fail to send messages.Expected behavior
Pick one contract and align both sides:
message.newWS fanout for realtime delivery.message.sendcommand, with the same auth, membership, idempotency, validation, and error semantics as REST.Acceptance criteria
message.new.