Skip to content

feat: record a subscribe issued with no attached Transport - #429

Merged
diegolmello merged 15 commits into
mobilefrom
diegolmello/fix-a-subscribe-issued-with-no-transport-attache
Sep 1, 2026
Merged

diegolmello merged 15 commits into
mobilefrom
diegolmello/fix-a-subscribe-issued-with-no-transport-attache

Conversation

@diegolmello

@diegolmello diegolmello commented Aug 31, 2026 •

Copy link
Copy Markdown
Member

Proposed changes

A subscribe issued while the Socket holds no attached Transport is now recorded instead of silently dropped. The discriminator is attachment, and only attachment: whether the Socket held an attached Transport at the moment of the send. No sub frame is composed, the entry is the instruction, and subscribeAll issues it once a Transport is attached. A Transport that is attached but never opened is unchanged, and so is the Socket's own refusal to send, which is not on this path.

The mechanism is one injected predicate on DDPSubscriptions, isOffline, alongside the existing close-generation thunk, wired by the Socket to report that it holds no attached Transport and that no close owns it.

Built on that rule:

  • unsubscribe with no attached Transport forgets the entry locally and resolves, sending nothing. An unknown id still rejects; the connected path is unchanged.
  • Socket.logout with no attached Transport and no close taken forgets every entry and clears the stored Login before resolving, so the next user does not inherit the previous user's streams. The close-owned branch still rejects and touches nothing.
  • The media-readiness gate keeps resolving false with no attached Transport: resubscribeWhenRecorded reads the same predicate and does not attempt, letting its Deadline resolve false. Without this a handle would read as acknowledgement and the gate would report ready with no connection.
  • ADR-0006 (write rule) is rewritten in place with the discriminator stated positively and first, plus the three likely misreadings; ADR-0012 (handle) has its now-false bullet and rationale corrected; ADR-0015 (close) covers all three logout paths; ADR-0005 (per-id serialisation) no longer implies an unsubscribe that never enters the wire. CONTEXT.md gains Offline sub, cited from the DDP subscription entry.

Consumer-visible log string change: [ddp] Subscribe not acknowledged is now [ddp] Subscribe not recorded.

A handle for an Offline sub names a stream that was never on the wire, and nothing in the Driver contract distinguishes it from one the server acknowledged.

Closes #424
Closes #425
Closes #426
Closes #427
Closes #428

Steps to reproduce

  • Start the SDK with no connection ever established
  • Subscribe to a stream: the call resolves a DDP subscription, no sub frame reaches the wire
  • Connect and log in: the recorded subscription is sent once on the new connection
  • Repeat with a subscribe issued during a Scheduled Reopen: the entry is re-sent on the replacement connection
  • While disconnected, unsubscribe that subscription: it resolves, the entry is forgotten, and a later Login sends nothing for it
  • While disconnected, logout: every entry and the stored Login are gone
  • While disconnected with both media entries recorded, call waitForNotifyUserMediaSubs: it resolves false and sends nothing

Tests

  • A subscribe during a Scheduled Reopen is recorded and re-sent on the replacement connection
  • A subscribe on a never-connected Socket is recorded under the id it will later be sent with and reaches no wire
  • The first Login re-sends a subscription recorded before the Socket ever connected
  • Two subscribes for one stream with no Transport attached share one entry and one sub frame
  • A callback passed to such a subscribe receives events once the stream is established
  • A subscribe issued while a close owns the Socket records nothing
  • Socket.close() still forgets every entry, including these
  • A refused sub still leaves no entry; an Abandoned sub still keeps its entry; a wait that expired on an attached Transport still leaves no entry
  • A method call with no Transport attached is still refused immediately
  • Unit-seam coverage of isOffline on the DDPSubscriptions harness, with the option required rather than defaulted
  • unsubscribe with no attached Transport forgets the entry, resolves, and sends nothing; an unrecorded id still rejects
  • unsubscribe with no attached Transport leaves nothing for a later Login's subscribeAll
  • logout on a never-connected Socket forgets every entry and clears the stored Login; the close-owned branch still rejects and touches nothing
  • The media gate resolves false with no Transport attached while both media entries are recorded, and sends no frame
  • Unit-seam coverage that resubscribeWhenRecorded sends nothing and resolves false with nothing attached while entries are present

@diegolmello
diegolmello merged commit 2a93a7a into mobile Sep 1, 2026
5 checks passed
@diegolmello
diegolmello deleted the diegolmello/fix-a-subscribe-issued-with-no-transport-attache branch September 1, 2026 14:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment