ARCPRuntime.acceptSession(over:) shuts down the job manager and removes the session from sessions at Sources/ARCP/Runtime/ARCPRuntime.swift:120, but it never removes subscriptions created by that session. SubscriptionManager stores subscriptions globally by id at Sources/ARCP/Runtime/SubscriptionManager.swift:14, and a SubscriptionRecord holds only a filter and send closure, so there is no owner-session metadata to clean up after the transport closes. A client that subscribes and then disconnects without sending unsubscribe leaves a stale closure in the runtime, and later outbound envelopes will continue trying to deliver subscribe.event messages to the closed transport.
Fix prompt: Track the owning session id for each subscription and remove or close all subscriptions owned by a session when acceptSession(over:) leaves its dispatch loop. The cleanup should send a subscribe.closed envelope when the transport is still writable, should avoid closing unrelated sessions' subscriptions, and should remove stale records even if sending the close notification fails. Add an integration test that opens a subscriber, registers a subscription, closes the transport without unsubscribe, emits a later event from another session, and asserts that the old subscription is no longer retained or invoked.
ARCPRuntime.acceptSession(over:)shuts down the job manager and removes the session fromsessionsatSources/ARCP/Runtime/ARCPRuntime.swift:120, but it never removes subscriptions created by that session.SubscriptionManagerstores subscriptions globally by id atSources/ARCP/Runtime/SubscriptionManager.swift:14, and aSubscriptionRecordholds only a filter and send closure, so there is no owner-session metadata to clean up after the transport closes. A client that subscribes and then disconnects without sendingunsubscribeleaves a stale closure in the runtime, and later outbound envelopes will continue trying to deliversubscribe.eventmessages to the closed transport.Fix prompt: Track the owning session id for each subscription and remove or close all subscriptions owned by a session when
acceptSession(over:)leaves its dispatch loop. The cleanup should send asubscribe.closedenvelope when the transport is still writable, should avoid closing unrelated sessions' subscriptions, and should remove stale records even if sending the close notification fails. Add an integration test that opens a subscriber, registers a subscription, closes the transport withoutunsubscribe, emits a later event from another session, and asserts that the old subscription is no longer retained or invoked.