Skip to content

[AIT-454] Implement MAP_CLEAR operation#122

Open
lawrence-forooghian wants to merge 2 commits intointegration/protocol-v6from
AIT-454-map-clear
Open

[AIT-454] Implement MAP_CLEAR operation#122
lawrence-forooghian wants to merge 2 commits intointegration/protocol-v6from
AIT-454-map-clear

Conversation

@lawrence-forooghian
Copy link
Collaborator

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

Implements the MAP_CLEAR operation as specified in ably/specification#432. Integration tests ported from ably/ably-js#2176.

Summary by CodeRabbit

  • New Features

    • Added a new map clearing operation that enables efficient removal of all entries from live maps while preserving overall data consistency and maintaining proper operation sequencing across the system.
  • Tests

    • Extended test coverage for the new map clearing operation with comprehensive scenarios covering state consistency verification, edge cases, and interactions with other map operations.

@lawrence-forooghian lawrence-forooghian changed the base branch from main to AIT-207-partial-object-sync March 10, 2026 14:27
@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e967ea41-b6f4-4ca0-93ac-1899a859ac4c

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This pull request adds support for a MAP_CLEAR operation to the Live Objects protocol, introducing a clearTimeserial field to track the highest serial that cleared a map. The implementation includes wire protocol marshaling, operation validation and application logic, and integration into the message handling pipeline.

Changes

Cohort / File(s) Summary
Wire Protocol & Data Models
Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift, Sources/AblyLiveObjects/Protocol/ObjectMessage.swift
Added mapClear operation case (value 6) to ObjectOperationAction enum with WireMapClear type for wire serialization. Introduced clearTimeserial field to WireObjectsMap and ObjectsMap with corresponding encode/decode paths.
Core Map Implementation
Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift
Implemented applyMapClearOperation handler to validate serials, update clearTimeserial, and prune data entries. Added short-circuit logic in MAP_SET and MAP_REMOVE to respect clearTimeserial. Introduced test-only accessors testsOnly_clearTimeserial and testsOnly_applyMapClearOperation.
Message Handling Integration
Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift
Extended known action cases to include .mapClear in object protocol message handling for local operation application on ACK.
Test Infrastructure & Coverage
Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift, Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift, Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift, Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift
Added factory methods for constructing test data with mapClear and clearTimeserial fields. Implemented comprehensive test suite covering clearTimeserial tracking, conditional operation application, serial comparison logic, and MAP_CLEAR integration with existing map operations.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A map once cluttered, now pristine and bright,
With clearTimeserial to set things right,
MAP_CLEAR hops in with a serial so true,
Pruning old entries through protocol anew!
From wire to logic, the design shines clear,
Our little rabbit cheers: "Cleanliness is here!" 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title directly and specifically describes the main implementation work: adding MAP_CLEAR operation support across wire protocol, domain, state management, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch AIT-454-map-clear
📝 Coding Plan
  • Generate coding plan for human review comments

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/122/AblyLiveObjects March 10, 2026 14:29 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 10, 2026 17:15 Inactive
@lawrence-forooghian
Copy link
Collaborator Author

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Mar 10, 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.

@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 10, 2026 17:25 Inactive
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/Protocol/WireObjectMessage.swift (1)

504-512: Move the access modifier to the extension declaration.

Line 504 adds a new non-test Swift extension without an explicit ACL on the extension itself, and the members then repeat internal.

♻️ Suggested cleanup
-extension WireMapClear: WireObjectCodable {
-    internal init(wireObject _: [String: WireValue]) throws(ARTErrorInfo) {
+internal extension WireMapClear: WireObjectCodable {
+    init(wireObject _: [String: WireValue]) throws(ARTErrorInfo) {
         // No fields to decode
     }
 
-    internal var toWireObject: [String: WireValue] {
+    var toWireObject: [String: WireValue] {
         [:]
     }
 }

As per coding guidelines, **/*.swift: Specify an explicit access control level (SwiftLint explicit_acl) for all declarations in Swift code (tests are exempt)andWhen extending a type, put the access level on the extension declaration rather than on each member (tests are exempt)`.

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

In `@Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift` around lines 504 -
512, The extension for WireMapClear declares members with the internal ACL; move
the access control to the extension itself by declaring the extension as
internal (e.g. internal extension WireMapClear: WireObjectCodable) and remove
the redundant internal modifiers from the initializer init(wireObject _:
[String: WireValue]) throws(ARTErrorInfo) and the computed property toWireObject
so the extension-level ACL applies to both members.
Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift (1)

535-544: Consider surfacing clearTimeserial in the higher-level map factories too.

objectsMap(...) now understands the new field, but mapObjectState(...)/mapObjectMessage(...) still can't build a cleared map directly, so tests already have to drop down to objectState(map:).

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

In `@Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift` around lines 535 -
544, Add a clearTimeserial parameter to the higher-level map factories so tests
can build cleared maps without calling objectState(map:); update
mapObjectState(...) and mapObjectMessage(...) signatures to accept
clearTimeserial: String? (default nil) and pass it through when creating the
underlying ObjectsMap via objectsMap(semantics:entries:clearTimeserial:) or when
calling objectState(map:), and update any internal calls to preserve the new
argument so existing callers remain backwards-compatible.
Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift (1)

167-202: Cover the new wire opcode with a round-trip test.

These assertions only prove that mapClear can be decoded when the field is present. Because the fixture still uses action: 0, they won't catch a broken MAP_CLEAR raw value or an omitted "mapClear": [:] on encode.

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

In `@Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift` around lines 167 -
202, Add a round-trip test that constructs a WireObjectOperation with the
MAP_CLEAR opcode (use the enum case .mapClear or its raw value instead of
action: 0) and a "mapClear": [:] field, then encode it to the wire dictionary
and decode it back asserting action == .known(.mapClear), objectId matches, and
mapClear is present; place this alongside or as a new test (e.g., in
WireObjectMessageTests/WireObjectOperation tests) so encode+decode will catch
any broken MAP_CLEAR raw value or omitted mapClear on encode.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift`:
- Around line 470-471: When zeroing the map, also clear the persisted RTLM25
serial: set clearTimeserial = nil inside the map-reset paths so stale serials
aren’t retained. Update the resetData(userCallbackQueue:) implementation and
resetDataToZeroValued() (and any other zero-root code path that currently resets
map contents) to explicitly assign clearTimeserial = nil immediately after the
map/state is cleared so subsequent MAP_SET/MAP_REMOVE/MAP_CLEAR operations use a
fresh serial.

---

Nitpick comments:
In `@Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift`:
- Around line 504-512: The extension for WireMapClear declares members with the
internal ACL; move the access control to the extension itself by declaring the
extension as internal (e.g. internal extension WireMapClear: WireObjectCodable)
and remove the redundant internal modifiers from the initializer init(wireObject
_: [String: WireValue]) throws(ARTErrorInfo) and the computed property
toWireObject so the extension-level ACL applies to both members.

In `@Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift`:
- Around line 535-544: Add a clearTimeserial parameter to the higher-level map
factories so tests can build cleared maps without calling objectState(map:);
update mapObjectState(...) and mapObjectMessage(...) signatures to accept
clearTimeserial: String? (default nil) and pass it through when creating the
underlying ObjectsMap via objectsMap(semantics:entries:clearTimeserial:) or when
calling objectState(map:), and update any internal calls to preserve the new
argument so existing callers remain backwards-compatible.

In `@Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift`:
- Around line 167-202: Add a round-trip test that constructs a
WireObjectOperation with the MAP_CLEAR opcode (use the enum case .mapClear or
its raw value instead of action: 0) and a "mapClear": [:] field, then encode it
to the wire dictionary and decode it back asserting action == .known(.mapClear),
objectId matches, and mapClear is present; place this alongside or as a new test
(e.g., in WireObjectMessageTests/WireObjectOperation tests) so encode+decode
will catch any broken MAP_CLEAR raw value or omitted mapClear on encode.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e50b0da5-1be4-4c6f-954e-15a37b1eda23

📥 Commits

Reviewing files that changed from the base of the PR and between 12faf8b and 15f8798.

📒 Files selected for processing (8)
  • Sources/AblyLiveObjects/Internal/InternalDefaultLiveMap.swift
  • Sources/AblyLiveObjects/Internal/InternalDefaultRealtimeObjects.swift
  • Sources/AblyLiveObjects/Protocol/ObjectMessage.swift
  • Sources/AblyLiveObjects/Protocol/WireObjectMessage.swift
  • Tests/AblyLiveObjectsTests/Helpers/TestFactories.swift
  • Tests/AblyLiveObjectsTests/InternalDefaultLiveMapTests.swift
  • Tests/AblyLiveObjectsTests/InternalDefaultRealtimeObjectsTests.swift
  • Tests/AblyLiveObjectsTests/WireObjectMessageTests.swift

@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 13:22 Inactive
Base automatically changed from AIT-207-partial-object-sync to integration/protocol-v6 March 11, 2026 14:45
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 16:33 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 21:51 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 23:17 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 23:27 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 11, 2026 23:58 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 12, 2026 02:50 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 12, 2026 02:53 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 12, 2026 18:39 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 12, 2026 20:19 Inactive
@github-actions github-actions bot temporarily deployed to staging/pull/122/AblyLiveObjects March 13, 2026 01:52 Inactive
@lawrence-forooghian lawrence-forooghian marked this pull request as ready for review March 13, 2026 02:02
lawrence-forooghian and others added 2 commits March 13, 2026 14:59
Make everything go via a single method that implements the RTLM4
definition.
Per spec commit a9f839b. Integration tests ported from JS commit
d2ddac6.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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