Arcp::Client#close sets @closed = true at lib/arcp/client.rb:214 before it attempts to send session.bye at lib/arcp/client.rb:216. Because send_envelope raises IOError, 'client closed' when @closed is true at lib/arcp/client.rb:200, the bye send always fails and is swallowed by the broad close rescue. The transport is closed afterward, so the peer eventually notices EOF, but it never receives the protocol-level close reason that the method accepts and the sessions guide says is sent.
Fix prompt: Send session.bye while the client still permits outbound frames, then mark the client closed before stopping tasks and closing the transport. Keep close idempotent and retain best-effort behavior when the transport is already broken. Add a unit or integration spec using MemoryTransport#sent to assert that client.close(reason: 'done') emits a session.bye envelope with the reason exactly once.
Arcp::Client#closesets@closed = trueatlib/arcp/client.rb:214before it attempts to sendsession.byeatlib/arcp/client.rb:216. Becausesend_enveloperaisesIOError, 'client closed'when@closedis true atlib/arcp/client.rb:200, the bye send always fails and is swallowed by the broad close rescue. The transport is closed afterward, so the peer eventually notices EOF, but it never receives the protocol-level close reason that the method accepts and the sessions guide says is sent.Fix prompt: Send
session.byewhile the client still permits outbound frames, then mark the client closed before stopping tasks and closing the transport. Keep close idempotent and retain best-effort behavior when the transport is already broken. Add a unit or integration spec usingMemoryTransport#sentto assert thatclient.close(reason: 'done')emits asession.byeenvelope with the reason exactly once.