Skip to content

[DX-1211] Add strictMode client option and granted-mode checks on subscribe and presence.get#505

Merged
umair-ably merged 2 commits into
mainfrom
DX-1211/strict-mode-granted-mode-checks
Jul 15, 2026
Merged

[DX-1211] Add strictMode client option and granted-mode checks on subscribe and presence.get#505
umair-ably merged 2 commits into
mainfrom
DX-1211/strict-mode-granted-mode-checks

Conversation

@umair-ably

@umair-ably umair-ably commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Author's Note

Extends spec to include new strictMode behaviour as implemented in ably/ably-js#2236. Spec changes highlight whether the error is thrown or logged for previously silent subscribe and presence errors caused by channel mode mismatches.


What: Specifies the behaviour when a client performs an operation whose effect depends on a channel mode the server did not grant: RealtimeChannel#subscribe without SUBSCRIBE (new RTL7i) and RealtimePresence#get without PRESENCE_SUBSCRIBE (new RTP11f). Adds a strictMode client option (TO3r) that selects between failing the operation (true) and the legacy silent result plus an ERROR-level log (false, the default), allowing SDKs to ship the fix additively before a future major version flips the default.

Why: Today these calls fail silently — presence.get() resolves with [] and subscribe() registers a listener that never fires. This is a significant DX trap for both humans and coding agents (see ably/ably-js#2236 for experiments quantifying agent failure rates: 50% unrecoverable → 0% with strict failures). The checks use the granted mode set (RTL4m), not the requested modes, so they also catch the case where a capability restriction caused the server to silently drop a requested mode.

Error codes: 90009 (subscribe_mode_not_enabled) and 91008 (presence_subscribe_mode_not_enabled) are already registered in ably-common.

Deliberately out of scope: presence enter/update/leave without the presence mode (the server NACKs those, so they are not silent); the ErrorInfo remediation/hint field ably-js attaches to these errors (naming under separate discussion); and the annotations mode check (RTAN4e), where ably-js already fails the call today — deviating from other SDKs, which log per the current spec text — so strictMode gating is not necessary there to preserve existing behaviour.

Reference implementation: ably/ably-js#2236.

🤖 Generated with Claude Code

… presence.get

New spec points TO3r (strictMode ClientOptions attribute), RTL7i
(RealtimeChannel#subscribe checks granted modes for SUBSCRIBE) and RTP11f
(RealtimePresence#get checks granted modes for PRESENCE_SUBSCRIBE), so that
operations whose effect depends on a channel mode the server did not grant
fail with an ErrorInfo (strictMode true) or log a warning while preserving
their legacy silent result (strictMode false, the default).

Reference implementation: ably/ably-js#2236.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions github-actions Bot temporarily deployed to staging/pull/505 July 14, 2026 14:51 Inactive
umair-ably added a commit to ably/ably-js that referenced this pull request Jul 14, 2026
…roposed spec points

Spec point IDs RTL7i1/RTL7i2 and RTP11f1/RTP11f2 are proposed in
ably/specification#505 and are provisional until that PR merges.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@umair-ably umair-ably requested a review from AndyTWF July 14, 2026 14:58
@umair-ably umair-ably marked this pull request as ready for review July 14, 2026 14:59
@umair-ably umair-ably changed the title Add strictMode client option and granted-mode checks on subscribe and presence.get [DX-1211] Add strictMode client option and granted-mode checks on subscribe and presence.get Jul 14, 2026
Comment thread specifications/api-docstrings.md Outdated
| useBinaryProtocol: Bool default true ||| TO3f | When `true`, the more efficient MsgPack binary encoding is used. When `false`, JSON text encoding is used. The default is `true`. |
| transportParams: [String: Stringifiable]? ||| RTC1f | A set of key-value pairs that can be used to pass in arbitrary connection parameters, such as [`heartbeatInterval`](https://ably.com/docs/realtime/connection#heartbeats) or [`remainPresentFor`](https://ably.com/docs/realtime/presence#unstable-connections). |
| addRequestIds: Bool default false ||| TO3p | When `true`, every REST request to Ably should include a random string in the `request_id` query string parameter. The random string should be a url-safe base64-encoding sequence of at least 9 bytes, obtained from a source of randomness. This request ID must remain the same if a request is retried to a fallback host. Any log messages associated with the request should include the request ID. If the request fails, the request ID must be included in the [`ErrorInfo`]{@link ErrorInfo} returned to the user. The default is `false`. |
| strictMode: Bool default false ||| TO3r | When `true`, operations that would otherwise fail silently, such as those gated on a granted channel mode, fail with an [`ErrorInfo`]{@link ErrorInfo} describing the cause. When `false`, the same operations log a warning and return their legacy result. The default is `false`. A future major version will change the default to `true`. |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
| strictMode: Bool default false ||| TO3r | When `true`, operations that would otherwise fail silently, such as those gated on a granted channel mode, fail with an [`ErrorInfo`]{@link ErrorInfo} describing the cause. When `false`, the same operations log a warning and return their legacy result. The default is `false`. A future major version will change the default to `true`. |
| strictMode: Bool default false ||| TO3r | When `true`, operations that would otherwise fail silently, such as those gated on a granted channel mode, will instead throw an [`ErrorInfo`]{@link ErrorInfo} describing the cause. When `false`, the same operations log a warning and return their legacy result. The default is `false`. A future major version will change the default to `true`. |

Comment thread specifications/features.md Outdated
- `(TO3o)` `plugins` `Dict<PluginType:Plugin>` A map between a `PluginType` and a `Plugin` object. The client library might downcast a `Plugin` to particular plugin type.
- `(TO3p)` `addRequestIds` boolean - defaults to false. If true, `RSC7c` applies
- `(TO3q)` `transportParams` \[String: Stringifiable\]? - defaults to null. Described in [RTC1f](#RTC1f)
- `(TO3r)` `strictMode` boolean - defaults to `false`. Controls the behaviour of certain operations that, for historical reasons, complete successfully even though the client is in a state in which the operation cannot have its intended effect, such as operations gated on a granted channel mode (see [`RTL7i`](#RTL7i), [`RTP11f`](#RTP11f)). It is intended that a future major version of the specification will change the default to `true`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a minor wording consideration - would we make StrictMode true, or would we just fix the underlying issues in a major release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good spot, reworded to highlight the strictMode behaviour becomes the default

@github-actions github-actions Bot temporarily deployed to staging/pull/505 July 15, 2026 08:49 Inactive
…on surviving the next major

Apply Andy's suggestion that strictMode operations "will instead throw" an
ErrorInfo, and say a future major adopts the strict behaviour by default
rather than that the default flips: whether v-next flips the strictMode
default or removes the option and fixes the underlying behaviour
unconditionally is not yet decided.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@umair-ably umair-ably force-pushed the DX-1211/strict-mode-granted-mode-checks branch from 36b13e3 to 36e1562 Compare July 15, 2026 08:52
umair-ably added a commit to ably/ably-js that referenced this pull request Jul 15, 2026
…ictMode default flips

Align with the TO3r wording agreed on ably/specification#505: a future major
adopts the strict behaviour by default, whether by changing the strictMode
default or by making the behaviour unconditional and retiring the option.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@umair-ably umair-ably requested a review from AndyTWF July 15, 2026 08:55
umair-ably added a commit to ably/ably-js that referenced this pull request Jul 15, 2026
…ictMode default flips

A future major makes the strict behaviour unconditional; don't imply the
strictMode option survives with a flipped default. Aligns with the TO3r
wording agreed on ably/specification#505.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@umair-ably umair-ably merged commit d3649b9 into main Jul 15, 2026
2 checks passed
@umair-ably umair-ably deleted the DX-1211/strict-mode-granted-mode-checks branch July 15, 2026 08:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants