Problem
The /mux WebSocket delivers terminal PTY data and a session-state channel (ch: sessions) to the frontend MuxProvider. The PTY path works. The session-state path did not: the server was sending thin CDC notification objects (seq, sessionId, eventType) that do not match the SessionPatch shape (id, status, activity, attentionLevel, lastActivityAt) the TypeScript consumer expects. As a result, the dashboard never received live session-state updates over the WebSocket -- it had to poll or wait for a page refresh.
Root cause
terminal.Manager subscribed to the CDC broadcaster but forwarded raw cdc.Event fields directly onto the wire. There was no concept of a SessionSource interface to resolve derived session state (PR facts + canonical lifecycle -> display status), and no attentionLevel mapping on the server side.
What this issue tracks
Wire the full CDC -> derived-state -> SessionPatch delivery path through /mux:
- Define a
SessionSource interface in the terminal package (clean boundary: terminal does not import the service layer)
- Implement
DeriveStatus in the domain package (it only uses domain types; pulling it out of the service layer removes the circular pressure)
- Implement
attentionLevel() server-side, mirroring getDetailedAttentionLevel in packages/web/src/lib/types.ts
- Build
daemonSessionSource in the daemon package: wraps the sqlite store + GetDisplayPRFactsForSession + DeriveStatus
- Move DB enrichment off the CDC broadcaster hot path (the broadcaster contract explicitly requires non-blocking callbacks)
- Close the subscribe/snapshot gap so no event is missed during initial connect
- Add full unit coverage for the attention-level mapping and functional integration tests for the end-to-end wire path
Problem
The
/muxWebSocket delivers terminal PTY data and a session-state channel (ch: sessions) to the frontendMuxProvider. The PTY path works. The session-state path did not: the server was sending thin CDC notification objects (seq,sessionId,eventType) that do not match theSessionPatchshape (id,status,activity,attentionLevel,lastActivityAt) the TypeScript consumer expects. As a result, the dashboard never received live session-state updates over the WebSocket -- it had to poll or wait for a page refresh.Root cause
terminal.Managersubscribed to the CDC broadcaster but forwarded rawcdc.Eventfields directly onto the wire. There was no concept of aSessionSourceinterface to resolve derived session state (PR facts + canonical lifecycle -> display status), and noattentionLevelmapping on the server side.What this issue tracks
Wire the full CDC -> derived-state ->
SessionPatchdelivery path through/mux:SessionSourceinterface in the terminal package (clean boundary: terminal does not import the service layer)DeriveStatusin thedomainpackage (it only uses domain types; pulling it out of the service layer removes the circular pressure)attentionLevel()server-side, mirroringgetDetailedAttentionLevelinpackages/web/src/lib/types.tsdaemonSessionSourcein the daemon package: wraps the sqlite store +GetDisplayPRFactsForSession+DeriveStatus