ArcpRuntime stores a new SessionLoop before the handshake under loop.idOrPending(), which is a pending UUID at arcp-runtime/src/main/java/dev/arcp/runtime/ArcpRuntime.java around line 109. After the handshake, SessionLoop.idOrPending() returns the real session id, so removeSession at line 192 removes with a different key and leaves the closed session in the sessions map. A runtime that accepts and closes many sessions will retain stale SessionLoop instances until the whole runtime is closed, and close() will also revisit sessions that were already shut down.
Fix prompt: Make the sessions map key stable across the SessionLoop lifecycle or update the map when the handshake assigns a SessionId. One straightforward fix is to keep the pending key in the SessionLoop and have removeSession remove that stored key, while a stronger fix is to add an ArcpRuntime callback invoked after handshake that atomically replaces the pending key with the real session id. Add a test that accepts a MemoryTransport pair, completes a handshake, closes the client, and asserts the runtime no longer retains the closed loop.
ArcpRuntime stores a new SessionLoop before the handshake under loop.idOrPending(), which is a pending UUID at arcp-runtime/src/main/java/dev/arcp/runtime/ArcpRuntime.java around line 109. After the handshake, SessionLoop.idOrPending() returns the real session id, so removeSession at line 192 removes with a different key and leaves the closed session in the sessions map. A runtime that accepts and closes many sessions will retain stale SessionLoop instances until the whole runtime is closed, and close() will also revisit sessions that were already shut down.
Fix prompt: Make the sessions map key stable across the SessionLoop lifecycle or update the map when the handshake assigns a SessionId. One straightforward fix is to keep the pending key in the SessionLoop and have removeSession remove that stored key, while a stronger fix is to add an ArcpRuntime callback invoked after handshake that atomically replaces the pending key with the real session id. Add a test that accepts a MemoryTransport pair, completes a handshake, closes the client, and asserts the runtime no longer retains the closed loop.