Skip to content

Decode live messages with the channel's current options - #1378

Merged
sacOO7 merged 3 commits into
integration/v2from
fix/realtime-live-decoding-options
Nov 2, 2026
Merged

sacOO7 merged 3 commits into
integration/v2from
fix/realtime-live-decoding-options

Conversation

@sacOO7

@sacOO7 sacOO7 commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Summary

A realtime channel decoded the messages it receives with a decoding context built once, from the options the channel was created with. SetOptions and Channels.Get(name, options) updated Options but never that context, so after a cipher change the channel published with the new cipher but still decrypted received messages with the old one, delivering them as byte[] with a residual cipher+... encoding. Presence, annotations, publishing and REST retrieval already used the current options. The bug dates from 1.x.

This PR also updates the README's Push.Admin note to mention the push-admin capability, matching UPDATING.md, CHANGELOG.md and the XML docs.

Fix

  • RealtimeChannel.Options setter: also set MessageDecodingContext.ChannelOptions. Every way of changing options goes through it (SetOptions, Channels.Get(name, options) on an existing channel, the AddOrUpdate path, direct assignment).
  • Constructor: build the context from Options (the normalised value) instead of the raw argument.
  • The context is updated in place, not replaced: it also holds the delta base payload (RTL19), which must survive an options change. Replacing it would make the next delta fail with "Missing previous payload" and trigger decode-failure recovery.
  • CHANGELOG 2.0 "Fixed bugs" entry.

Tests

New ChannelOptionsDecodingSpecs (8 tests, fake transport):

Test integration/v2 This PR
SetOptions adding a cipher fail pass
SetOptions changing the cipher fail pass
Channels.Get(name, options) on an existing channel (RTS3c) fail pass
Direct Options setter (AES-256 to AES-128) fail pass
SetOptions without a cipher stops decryption fail pass
Encrypted delta across a key change keeps the delta base (RTL19/RTL20) fail pass
Presence after a cipher change (regression guard) pass pass
Annotations after a cipher change (regression guard) pass pass

With the context replaced instead of updated, only the delta test fails (the delta is dropped and the channel goes to ATTACHING).

Validation

All on ecdbd77d (the pushed head):

  • ./build.sh --target=Build.NetStandard: build succeeded, 0 warnings, 0 errors.
  • ./build.sh --target=Test.NetStandard.Unit.WithRetry --framework=net6.0: 1515 total, 1496 passed, 19 skipped, 0 failed.
  • An independent review re-ran the fail-before, pass-after and replace-the-context checks above, both gates (same totals), and checked the change against RTL16, RTS3c, RSL5a, RTL19 and ably-java: pass.

Spec and ably-java

  • RTL16: setOptions "sets or updates the stored channel options"; with no params or modes it "indicates success immediately" (RTL16a), so a cipher-only change must apply to the next received message.
  • RTS3c: Channels#get(channel, options) on an existing channel "will update the options on the channel".
  • RSL5a: with a cipher, payloads are "decrypted when received on this channel".
  • RTL19: the base payload "must be stored at all times"; it is captured before decryption, so it does not depend on the key.
  • ably-java does the same: ChannelBase passes the current options to msg.decode(options, decodingContext) for every message, and its DecodingContext (delta base only) is created once and kept across setOptions.

Summary by CodeRabbit

  • Bug Fixes

    • Realtime channels now use their current options to decrypt received messages, presence updates, and annotations. Adding, changing, or removing a cipher takes effect for subsequent decoding, while delta messages continue to use the correct stored base.
  • Documentation

    • Clarified that Push.Admin is intended for server-side use, requires the push-admin capability, and is available through both device and server clients. The README recommends using it from a backend.

A realtime channel decoded received messages with a decoding context
built once from the options it was created with, so SetOptions and
Channels.Get(name, options) never changed the cipher used for them
(RTL16, RTS3c). Presence, annotations and publishing already used the
current options.

Update the context's options whenever the channel's options change,
rather than replacing the context, which also holds the delta base
payload that must survive the change (RTL19).
@coderabbitai

coderabbitai Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 1 minute.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: fdf27883-edbf-49ba-bc32-000087cbd72d
Commits

Reviewing files that changed from the base of the PR and between ecdbd77 and dadf2b9.

Files selected for processing: 5
  • CHANGELOG.md
  • README.md
  • src/Ably.PubSub.Shared/Realtime/RealtimeChannel.cs
  • src/Ably.PubSub.Tests.Shared/Ably.PubSub.Tests.Shared.projitems
  • src/Ably.PubSub.Tests.Shared/Realtime/ChannelOptionsDecodingSpecs.cs

No actionable comments were generated in the recent review.

Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5a051e25-5a18-455e-ba89-a5f10fa961f1
Commits

Reviewing files that changed from the base of the PR and between fd4de79 and ecdbd77.

Files selected for processing: 5
  • CHANGELOG.md
  • README.md
  • src/Ably.PubSub.Shared/Realtime/RealtimeChannel.cs
  • src/Ably.PubSub.Tests.Shared/Ably.PubSub.Tests.Shared.projitems
  • src/Ably.PubSub.Tests.Shared/Realtime/ChannelOptionsDecodingSpecs.cs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Walkthrough

Realtime channels now update message decoding options when channel options change. Tests cover message, presence, annotation, and delta decoding. The README also clarifies Push.Admin availability and capability requirements.

Changes

Channel Decoding Options

Layer / File(s) Summary
Update decoding options
src/Ably.PubSub.Shared/Realtime/RealtimeChannel.cs, CHANGELOG.md
The Options setter updates an existing decoding context. The constructor initializes the context from normalized options. The changelog records decoding with current channel options.
Verify current-options decoding
src/Ably.PubSub.Tests.Shared/Realtime/ChannelOptionsDecodingSpecs.cs, src/Ably.PubSub.Tests.Shared/Ably.PubSub.Tests.Shared.projitems
The shared tests cover cipher changes through SetOptionsAsync, Channels.Get, and the Options setter. They also cover cipher removal, delta payloads, presence, and annotations.

Push.Admin Usage Note

Layer / File(s) Summary
Document Push.Admin requirements
README.md
The README states that Push.Admin is available on Device and Server clients, requires the push-admin capability, and is intended for use from a Server backend.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related PRs

Suggested reviewers: umair-ably, ttypic

Merge Risk: Minimal · previous review ecdbd

Channels use current decoding options while retaining the existing context. No material merge risk was identified.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: realtime messages now decode using the channel's current options.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 3 functions across 2 files. (3 skipped: 3 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

Finishing Touches
Generate docstrings
  • Commit to this branch
  • Create a new PR
Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

A rabbit checks the cipher's key,
As channel options change with care.
New messages shed their coded coat,
Presence and notes decode just so.
Then off I hop, with bytes to spare.

@sacOO7
sacOO7 merged commit ddf0304 into integration/v2 Nov 2, 2026
21 checks passed
@sacOO7
sacOO7 deleted the fix/realtime-live-decoding-options branch November 2, 2026 13:54
@sacOO7 sacOO7 mentioned this pull request Nov 2, 2026

This branch was successfully deployed

1 active deployment
staging/pull/1378/features — dadf2b9b Deployed Nov 2, 2026 by github-actions[bot]
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.

1 participant