Skip to content

[AIT-287] Implement new rules for discarding ops buffered during sync#121

Merged
lawrence-forooghian merged 2 commits intomainfrom
AIT-287-new-rules-for-discarding-buffered-events
Mar 11, 2026
Merged

[AIT-287] Implement new rules for discarding ops buffered during sync#121
lawrence-forooghian merged 2 commits intomainfrom
AIT-287-new-rules-for-discarding-buffered-events

Conversation

@lawrence-forooghian
Copy link
Collaborator

@lawrence-forooghian lawrence-forooghian commented Mar 5, 2026

Note: This PR is based on top of #118; please review that one first.

Implements ably/specification@997584f. Integration tests ported from ably/ably-js@9b2224d.

Summary by CodeRabbit

  • Tests

    • Expanded and clarified tests for channel ATTACHED behavior, HAS_OBJECTS flags, and buffered object operation handling across sync/resume scenarios.
  • Refactor

    • Adjusted runtime handling of buffered object operations and ATTACHED/sync transitions to ensure consistent clearing/preserving of buffered operations.

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

Walkthrough

Refines OBJECT operation buffering and sync state transitions: preserves buffered operations when continuing an existing sync sequence, clears buffers on channel ATTACHED or when starting a new sync, and exposes an internal test accessor for buffered count. Tests and integration calls updated to use flag-based ATTACHED messages.

Changes

Cohort / File(s) Summary
Core Sync Buffer Logic
Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift
Added internal var testsOnly_bufferedObjectOperationsCount: Int?; changed channel-attach and object-sync handling so buffers are cleared on ATTACHED or when starting a new sync, while preserving buffered operations when continuing an existing sync sequence; removed unconditional buffer clears in the continue-sync path and adjusted related labels/comments.
Unit Test Updates
Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift
Renamed doesNotModifyStateWhenHasObjectsIsTruehandlesHasObjectTrue; removed tests tied to removed RTO5a2b path; added assertions for bufferedObjectOperationsCount during and after sync/attach flows; updated spec annotations to reference RTO4d/RTO4a where applicable.
Integration Test API & Expansion
Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsIntegrationTests.swift
Changed injectAttachedMessage signature from hasObjects: Bool to flags: ARTProtocolMessageFlag = []; set pm.flags = Int64(flags.rawValue) and updated all call sites to use flag values (e.g., .hasObjects, [.hasObjects, .resumed]); expanded scenarios to validate ATTACHED handling and buffering/discarding semantics across flag combinations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

🐇 I nibbled at buffers under moonlit sync,

kept gentle what stayed and cleared what must shrink.
Flags on the channel waved crisp and true,
tests hopped along to prove what we do.
A tiny rabbit cheers the tidy queue! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: implementing new rules for discarding buffered operations during sync.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch AIT-287-new-rules-for-discarding-buffered-events

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot temporarily deployed to staging/pull/121/AblyLiveObjects March 5, 2026 18:19 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the AIT-287-new-rules-for-discarding-buffered-events branch from 07ffcf9 to 047959f Compare March 5, 2026 18:37
@github-actions github-actions bot temporarily deployed to staging/pull/121/AblyLiveObjects March 5, 2026 18:39 Inactive
@lawrence-forooghian lawrence-forooghian force-pushed the AIT-287-new-rules-for-discarding-buffered-events branch from 047959f to 65dda76 Compare March 5, 2026 18:50
@github-actions github-actions bot temporarily deployed to staging/pull/121/AblyLiveObjects March 5, 2026 18:52 Inactive
@lawrence-forooghian
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 5, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift (1)

87-87: Remove the generic comment on the testsOnly_ property.

Line 87 adds a generic explanatory comment for a testsOnly_ declaration; repo guidance asks to omit these in Sources/**/*.swift.

✂️ Suggested cleanup
-    /// Returns the number of buffered object operations if in the SYNCING state, or nil otherwise.
     internal var testsOnly_bufferedObjectOperationsCount: Int? {

As per coding guidelines, Sources/**/*.swift: “For testsOnly_ property declarations, do not add generic explanatory comments (their meaning is understood)”.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift` at
line 87, Remove the generic explanatory comment added for the testsOnly_
property; locate the testsOnly_ declaration in InternalDefaultRealtimeObjects
(the testsOnly_ property in InternalDefaultRealtimeObjects.swift) and delete the
comment above it so the property has no generic explanatory comment per
Sources/**/*.swift guidelines.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Tests/AblyLiveObjectsTests/JS` Integration
Tests/ObjectsIntegrationTests.swift:
- Around line 607-622: This test case is missing the required spec-point
attribution comment; add an exact-format comment (either // `@spec`(<section
reference>) or // `@specPartial`(<section reference>)) immediately above the
.init( ... ) test declaration that references the relevant spec point governing
ATTACHED without HAS_OBJECTS behavior, choosing `@spec` vs `@specPartial` per the
guideline and avoid duplicating the same `@spec` tag elsewhere for the same spec
point; ensure the comment is placed in the same test block that contains the
action closure (the anonymous .init with description "on ATTACHED without
HAS_OBJECTS clears local state") so tools can associate it with that test.

---

Nitpick comments:
In `@Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift`:
- Line 87: Remove the generic explanatory comment added for the testsOnly_
property; locate the testsOnly_ declaration in InternalDefaultRealtimeObjects
(the testsOnly_ property in InternalDefaultRealtimeObjects.swift) and delete the
comment above it so the property has no generic explanatory comment per
Sources/**/*.swift guidelines.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6f3ee39a-112d-4dbd-b002-94cd53865bdc

📥 Commits

Reviewing files that changed from the base of the PR and between cbb49fd and 65dda76.

📒 Files selected for processing (3)
  • Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift
  • Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift
  • Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsIntegrationTests.swift

@lawrence-forooghian lawrence-forooghian marked this pull request as ready for review March 5, 2026 19:28
Port of ably-js commit b329fd2. Verifies that when an ATTACHED message
is received without the HAS_OBJECTS flag, the SDK clears all local
LiveObjects state (root map should have no keys).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lawrence-forooghian lawrence-forooghian force-pushed the AIT-287-new-rules-for-discarding-buffered-events branch from 65dda76 to 343e8cf Compare March 9, 2026 16:49
@github-actions github-actions bot temporarily deployed to staging/pull/121/AblyLiveObjects March 9, 2026 16:51 Inactive
Base automatically changed from AIT-324-apply-on-ACK to main March 11, 2026 11:36
Implements spec commit 997584f. Integration tests ported from ably-js
commit 9b2224d.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift (2)

87-88: Drop the generic doc comment on this testsOnly_ accessor.

The name already carries the intent, so this extra sentence just adds noise.

✂️ Suggested cleanup
-    /// Returns the number of buffered object operations if in the SYNCING state, or nil otherwise.
     internal var testsOnly_bufferedObjectOperationsCount: Int? {

As per coding guidelines, "For testsOnly_ property declarations, do not add generic explanatory comments (their meaning is understood)."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift` around
lines 87 - 88, Remove the generic doc comment above the internal property
testsOnly_bufferedObjectOperationsCount; the name already documents intent, so
delete the comment block (the triple-slash/`///` line) immediately preceding the
internal var testsOnly_bufferedObjectOperationsCount declaration in
InternalDefaultRealtimeObjects so only the property remains.

802-804: Make the discard scope explicit here.

After the referenced spec change, RTO5a2a only discards the in-flight sync sequence state; buffered OBJECT ops were moved under RTO4d on ATTACHED. “discard previous” reads broader than what this branch now does and makes it easy to reintroduce the old buffer reset by accident. (github.com)

📝 Suggested wording
-                    // RTO5a2a: new sequence started, discard previous. Else we continue the existing sequence per RTO5a3
+                    // RTO5a2a: new sequence started, discard the previous in-flight sync sequence.
+                    // bufferedObjectOperations are cleared on ATTACHED per RTO4d, not here.
                     syncingData.syncSequence = nil
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift` around
lines 802 - 804, The comment for RTO5a2a is too broad; update it to explicitly
state that only the in‑flight sync sequence state (syncingData.syncSequence) is
being discarded here and that buffered OBJECT ops must NOT be reset in this
branch (buffer clearing is handled under RTO4d on ATTACHED). Locate the line
referencing RTO5a2a and syncingData.syncSequence and amend the comment to
reflect this narrower scope so future changes won't accidentally clear buffered
ops.
Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift (1)

421-421: Exercise RTO4d on the hasObjects == false path too.

RTO4d now owns buffered-operation disposal for every ATTACHED, and the old RTO5a2b clause was explicitly replaced. This case never makes bufferedObjectOperations non-empty, so the false branch can regress without the test failing. (github.com)

🧪 Suggested coverage addition
             `#expect`(realtimeObjects.testsOnly_hasSyncSequence)
             `#expect`(originalPool.entries.count == 3) // root + 2 additional objects

+            internalQueue.ably_syncNoDeadlock {
+                realtimeObjects.nosync_handleObjectProtocolMessage(objectMessages: [
+                    TestFactories.mapCreateOperationMessage(objectId: "map:buffered@999"),
+                ])
+            }
+            `#expect`(realtimeObjects.testsOnly_bufferedObjectOperationsCount == 1)
+
             // When: onChannelAttached is called with hasObjects = false
             internalQueue.ably_syncNoDeadlock {
                 realtimeObjects.nosync_onChannelAttached(hasObjects: false)
             }
@@
             // RTO4b3, RTO4b4, RTO4d: SyncObjectsPool must be cleared, sync sequence cleared, BufferedObjectOperations cleared, appliedOnAckSerials cleared
             `#expect`(!realtimeObjects.testsOnly_hasSyncSequence)
+            `#expect`(realtimeObjects.testsOnly_bufferedObjectOperationsCount == nil)
             `#expect`(realtimeObjects.testsOnly_appliedOnAckSerials.isEmpty)

Also applies to: 497-499

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift` at line
421, Update the test to also exercise the RTO4d behavior when hasObjects ==
false: in InternalDefaultRealtimeObjectsTests add a run that simulates an
ATTACHED state with hasObjects set to false and verify that
bufferedObjectOperations remains empty (and any disposal logic invoked) so the
new RTO4d buffered-operation disposal path is executed; specifically modify the
test(s) around the RTO4d checks (and the similar cases at the region identified
for lines 497-499) to create an ATTACHED lifecycle transition with hasObjects ==
false and assert the same disposal/clear expectations as the true branch (refer
to symbols RTO4d, hasObjects, bufferedObjectOperations and the replaced RTO5a2b
behavior).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Tests/AblyLiveObjectsTests/JS` Integration
Tests/ObjectsIntegrationTests.swift:
- Around line 2297-2316: The test currently only checks final state after
calling objectsHelper.processObjectStateMessageOnChannel(... syncSerial:
"serial:") so add an intermediate assertion after the injected operation (and
after ATTACHED is processed) but before calling
processObjectStateMessageOnChannel to verify the post-ATTACHED operation remains
buffered: either assert the buffered-op count via the new buffered-count
accessor on the object or assert that root.get(key: "baz") is still nil; then
keep the existing final assertion that after processObjectStateMessageOnChannel
the buffered op has been applied. Reference
processObjectOperationMessageOnChannel, processObjectStateMessageOnChannel and
root.get when placing the new check.

---

Nitpick comments:
In `@Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift`:
- Around line 87-88: Remove the generic doc comment above the internal property
testsOnly_bufferedObjectOperationsCount; the name already documents intent, so
delete the comment block (the triple-slash/`///` line) immediately preceding the
internal var testsOnly_bufferedObjectOperationsCount declaration in
InternalDefaultRealtimeObjects so only the property remains.
- Around line 802-804: The comment for RTO5a2a is too broad; update it to
explicitly state that only the in‑flight sync sequence state
(syncingData.syncSequence) is being discarded here and that buffered OBJECT ops
must NOT be reset in this branch (buffer clearing is handled under RTO4d on
ATTACHED). Locate the line referencing RTO5a2a and syncingData.syncSequence and
amend the comment to reflect this narrower scope so future changes won't
accidentally clear buffered ops.

In `@Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift`:
- Line 421: Update the test to also exercise the RTO4d behavior when hasObjects
== false: in InternalDefaultRealtimeObjectsTests add a run that simulates an
ATTACHED state with hasObjects set to false and verify that
bufferedObjectOperations remains empty (and any disposal logic invoked) so the
new RTO4d buffered-operation disposal path is executed; specifically modify the
test(s) around the RTO4d checks (and the similar cases at the region identified
for lines 497-499) to create an ATTACHED lifecycle transition with hasObjects ==
false and assert the same disposal/clear expectations as the true branch (refer
to symbols RTO4d, hasObjects, bufferedObjectOperations and the replaced RTO5a2b
behavior).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: a475bc14-3f64-4cdd-bddf-57a5df8d9f92

📥 Commits

Reviewing files that changed from the base of the PR and between 65dda76 and f15cfac.

📒 Files selected for processing (3)
  • Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift
  • Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift
  • Tests/AblyLiveObjectsTests/JS Integration Tests/ObjectsIntegrationTests.swift

Copy link

@ttypic ttypic left a comment

Choose a reason for hiding this comment

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

LGTM

@lawrence-forooghian lawrence-forooghian merged commit 4df4816 into main Mar 11, 2026
18 checks passed
@lawrence-forooghian lawrence-forooghian deleted the AIT-287-new-rules-for-discarding-buffered-events branch March 11, 2026 13:38
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