Files
Max Isbey 8ca1fc628d Serve subscriptions/listen over the dual-era stream loop
Remove the transport-level rejection of subscriptions/listen on the
stream-pair modern path: the method now dispatches through serve_one to
the registered ListenHandler like every other modern request. Over
stdio the listen request simply stays pending - the ack and every event
are request-scoped notifications on the duplex pipe, and the response
arrives only when the stream ends gracefully. server/discover's
subscription capability advertisement is now truthful on this transport.

Two era-scoped generalizations ride the dispatcher's new per-request
seams, fixing the class rather than the listen instance:

- Era lock at first client-visible success frame. A classified-modern
  request commits the modern lock immediately before its first
  non-error frame is written (notification, progress, or response),
  not when its dispatch returns. Plain requests lock at their response
  exactly as before; a listen locks at its ack, so an initialize
  pipelined behind a live stream is rejected with -32022 instead of
  flipping the connection legacy mid-stream. Classification failures
  and pre-frame cancellations still never lock, and progress written
  for a request that later fails locks correctly (the client that
  stamped a valid envelope already committed to modern).

- Quiet cancellation for every classified-modern request. After an
  inbound notifications/cancelled the server sends nothing further for
  that request - no result, no error - matching the transport spec's
  MUST NOT. Legacy-era requests keep the byte-identical code-0
  "Request cancelled" answer released 2025 clients unblock on.

The single-exchange HTTP and direct in-process paths need no seam:
cancellation is structurally silent there (stream close / caller's own
scope).
2026-07-16 21:22:55 +00:00
..