Skip to content

[ECO-5438] Add the soft delete behaviour and validation loosening - #330

Merged
maratal merged 1 commit into
mainfrom
321-soft-deletes-and-validation-loosening
Jul 22, 2025
Merged

[ECO-5438] Add the soft delete behaviour and validation loosening#330
maratal merged 1 commit into
mainfrom
321-soft-deletes-and-validation-loosening

Conversation

@maratal

@maratal maratal commented Jul 12, 2025

Copy link
Copy Markdown
Contributor

Closes #321

Add the soft delete behaviour and validation loosening
Fix room reaction tests.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of malformed or incomplete chat and reaction events, ensuring default values are used and errors are logged instead of causing failures.
    • Ensured message metadata is never nil in updated and deleted messages.
  • Refactor

    • Streamlined error handling in message and reaction event processing for greater robustness and clarity.
    • Updated internal data handling to use optional values and fallbacks for missing fields.
    • Removed throwing initializers and replaced error propagation with silent fallback defaults during JSON decoding.
  • Tests

    • Enhanced tests to verify that events with incomplete data are still emitted with default values.
    • Updated test cases and assertions to match new data handling logic.
    • Improved subscription tracking and callback invocation assertions.
  • New Features

    • Added a utility method for mapping annotation actions to reaction events.

@coderabbitai

coderabbitai Bot commented Jul 12, 2025

Copy link
Copy Markdown

Walkthrough

This update refactors error handling in message and reaction event processing throughout the chat system. Throwing guards and do-catch blocks are replaced with logging, early returns, and default fallbacks. Several initializers and methods are made non-throwing, and public entity signatures are updated to use optional types and defaults, improving resilience to malformed or incomplete data.

Changes

File(s) Change Summary
Sources/AblyChat/DefaultMessageReactions.swift, Sources/AblyChat/DefaultRoomReactions.swift, Sources/AblyChat/DefaultMessages.swift Refactored event processing to remove throwing guards and do-catch blocks; added logging, early returns, and fallback defaults for malformed data.
Sources/AblyChat/MessageReaction+JSON.swift Made MessageReactionSummary initializer non-throwing; replaced error propagation with silent fallback to empty dictionaries on decode failure.
Sources/AblyChat/MessageReaction.swift Added extension: MessageReactionEvent.fromAnnotationAction(_:) for mapping annotation actions to reaction events.
Sources/AblyChat/Message.swift Changed MessageOperation.clientID to optional; updated initializer to accept optional clientID.
Sources/AblyChat/ChatAPI.swift Ensured operation.metadata is never nil in updateMessage and deleteMessage.
Tests/AblyChatTests/DefaultMessagesTests.swift, Tests/AblyChatTests/DefaultRoomReactionsTests.swift Updated and renamed tests to reflect new error handling and default value logic; expanded assertions and coverage.
Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift Always appends subscription callbacks for consistent tracking, regardless of immediate message emission.

Sequence Diagram(s)

sequenceDiagram
    participant AblyChannel
    participant DefaultMessages
    participant Subscriber

    AblyChannel->>DefaultMessages: Receive message event
    DefaultMessages->>DefaultMessages: Validate fields (no throw)
    alt Malformed or missing data
        DefaultMessages->>DefaultMessages: Log and use default values
    end
    DefaultMessages->>Subscriber: Emit Message (with defaults if needed)
Loading
sequenceDiagram
    participant AblyChannel
    participant DefaultMessageReactions
    participant Subscriber

    AblyChannel->>DefaultMessageReactions: Receive reaction event
    DefaultMessageReactions->>DefaultMessageReactions: Validate action and type
    alt Unknown action/type
        DefaultMessageReactions->>DefaultMessageReactions: Log and return early
    else Valid event
        DefaultMessageReactions->>Subscriber: Emit Reaction Event
    end
Loading

Possibly related PRs

Suggested reviewers

  • lawrence-forooghian
  • umair-ably

Poem

🐇 In code’s wild meadow, errors fade,
No throws to scare, no fears to trade.
Logs light the path, defaults in tow,
Messages flow with gentle glow.
Reactions dance, all safe and sound—
A rabbit’s fix, so swift, profound! 🌿✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af1c2f5 and 6e8bc65.

📒 Files selected for processing (10)
  • Sources/AblyChat/ChatAPI.swift (2 hunks)
  • Sources/AblyChat/DefaultMessageReactions.swift (3 hunks)
  • Sources/AblyChat/DefaultMessages.swift (2 hunks)
  • Sources/AblyChat/DefaultRoomReactions.swift (1 hunks)
  • Sources/AblyChat/Message.swift (2 hunks)
  • Sources/AblyChat/MessageReaction+JSON.swift (4 hunks)
  • Sources/AblyChat/MessageReaction.swift (2 hunks)
  • Tests/AblyChatTests/DefaultMessagesTests.swift (3 hunks)
  • Tests/AblyChatTests/DefaultRoomReactionsTests.swift (1 hunks)
  • Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift
  • Sources/AblyChat/ChatAPI.swift
  • Sources/AblyChat/DefaultRoomReactions.swift
  • Sources/AblyChat/MessageReaction.swift
  • Sources/AblyChat/MessageReaction+JSON.swift
  • Sources/AblyChat/DefaultMessageReactions.swift
  • Sources/AblyChat/Message.swift
  • Tests/AblyChatTests/DefaultMessagesTests.swift
  • Tests/AblyChatTests/DefaultRoomReactionsTests.swift
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultMessages.swift:141-147
Timestamp: 2025-05-12T21:08:08.048Z
Learning: Swift 6 supports typed throws in do blocks using the syntax `do throws(ErrorType)` as part of SE-0413, allowing developers to explicitly specify which error types can be thrown from within the block, providing improved type safety and eliminating the need for type casting in catch blocks.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultMessages.swift:141-147
Timestamp: 2025-05-12T21:08:08.048Z
Learning: Swift 6 supports typed throws in do blocks with syntax `do throws(ErrorType)` as part of SE-0413, allowing specification of concrete error types that can be thrown within the block.
Sources/AblyChat/DefaultMessages.swift (11)
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionHandleStorage.swift:37-40
Timestamp: 2025-05-12T21:02:28.274Z
Learning: In the AblyChat Swift codebase, the `SubscriptionHandle` struct has an `unsubscribe()` method for terminating subscriptions, not a `cancel()` method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomReactions.swift:42-56
Timestamp: 2025-05-16T21:35:46.634Z
Learning: In the AblyChat framework, all subscription callbacks are annotated with @MainActor, ensuring they always execute on the main actor thread without requiring additional Task wrappers.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription callbacks continue to work even when the handle is not stored, as the underlying services maintain their own storage of callbacks that remain registered until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription continues to work even if the handle is not stored, as the underlying services maintain references to the callbacks until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomLifecycleManager.swift:611-624
Timestamp: 2025-05-22T20:57:48.147Z
Learning: In AblyChat Swift, when using continuations with subscription callbacks, the continuation object is captured directly by the closure and doesn't depend on `self`. Even with `[weak self]` capture, the continuation will still be resumed properly.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (34)
  • GitHub Check: Example app, macOS (Xcode 16.3)
  • GitHub Check: Example app, tvOS (Xcode 16.3)
  • GitHub Check: Example app, tvOS (Xcode 16.2)
  • GitHub Check: Example app, iOS (Xcode 16.3)
  • GitHub Check: Xcode, tvOS (Xcode 16.3)
  • GitHub Check: Xcode, release configuration, iOS (Xcode 16.3)
  • GitHub Check: Example app, macOS (Xcode 16.1)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 16.1)
  • GitHub Check: Example app, iOS (Xcode 16.1)
  • GitHub Check: Xcode, release configuration, iOS (Xcode 16.2)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 16.2)
  • GitHub Check: Xcode, release configuration, tvOS (Xcode 16.3)
  • GitHub Check: Example app, tvOS (Xcode 16.1)
  • GitHub Check: Example app, macOS (Xcode 16.2)
  • GitHub Check: Xcode, macOS (Xcode 16.3)
  • GitHub Check: Example app, iOS (Xcode 16.2)
  • GitHub Check: Xcode, iOS (Xcode 16.3)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 16.3)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 16.2)
  • GitHub Check: Xcode, release configuration, iOS (Xcode 16.1)
  • GitHub Check: Xcode, release configuration, macOS (Xcode 16.1)
  • GitHub Check: Xcode, iOS (Xcode 16.1)
  • GitHub Check: SPM, release configuration (Xcode 16.3)
  • GitHub Check: Xcode, macOS (Xcode 16.2)
  • GitHub Check: Xcode, iOS (Xcode 16.2)
  • GitHub Check: Xcode, tvOS (Xcode 16.2)
  • GitHub Check: Xcode, tvOS (Xcode 16.1)
  • GitHub Check: Xcode, macOS (Xcode 16.1)
  • GitHub Check: SPM, release configuration (Xcode 16.2)
  • GitHub Check: SPM (Xcode 16.2)
  • GitHub Check: SPM (Xcode 16.1)
  • GitHub Check: SPM, release configuration (Xcode 16.1)
  • GitHub Check: SPM (Xcode 16.3)
  • GitHub Check: Generate code coverage
🔇 Additional comments (2)
Sources/AblyChat/DefaultMessages.swift (2)

83-117: Excellent refactoring to improve resilience against malformed data.

The systematic replacement of throwing guards with conditional logging and default fallbacks significantly improves the robustness of message processing. This approach ensures that malformed messages don't crash subscriptions while still providing visibility through logging.

The default values chosen are semantically reasonable:

  • Empty strings for missing text, serial, clientID, version
  • Empty dictionaries for missing metadata, headers, extras
  • Epoch/current time for missing timestamps

This aligns well with the "validation loosening" objective and the CHA-M specification requirements mentioned in the comments.


227-233: Consistent refactoring maintains coherent error handling approach.

The conversion of toChatOperation() from a throwing to non-throwing method with sensible defaults is perfectly aligned with the broader refactoring in the subscription handler. Using empty string for missing clientId and empty dictionary for missing metadata maintains consistency across the codebase.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 321-soft-deletes-and-validation-loosening

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 12, 2025 22:31 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from e3dd0f4 to c2101df Compare July 13, 2025 21:05
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 13, 2025 21:06 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from c2101df to 1b20ecc Compare July 14, 2025 13:09
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 13:11 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 1b20ecc to 1584625 Compare July 14, 2025 13:35
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 13:36 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 1584625 to 24f4aa2 Compare July 14, 2025 13:39
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 13:41 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 24f4aa2 to 4539d1a Compare July 14, 2025 13:57
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 13:58 Inactive
@maratal

maratal commented Jul 14, 2025

Copy link
Copy Markdown
Contributor Author

Spec coverage fails

Error: conformanceToNonexistentSpecPoints(specPointIDs: ["CHA-M4k", "CHA-M4k1", "CHA-M4k2", "CHA-M4k3", "CHA-M4k4"])

because ably/specification#339 is still opened.

@maratal
maratal marked this pull request as ready for review July 14, 2025 14:06
@maratal
maratal requested review from lawrence-forooghian, ttypic and umair-ably and removed request for lawrence-forooghian and umair-ably July 14, 2025 14:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
Sources/AblyChat/DefaultMessages.swift (1)

115-124: Consider using the same Date instance for both timestamp fields

The default values are appropriate for handling incomplete data. However, for consistency, consider capturing the current date once and using it for both fields when timestamps are missing:

+                    let defaultTimestamp = Date()
                     let message = try Message(
                         serial: message.serial ?? "", // CHA-M4k1
                         action: action,
                         clientID: message.clientId ?? "", // CHA-M4k1
                         text: text,
-                        createdAt: message.timestamp ?? Date(), // CHA-M4k4
+                        createdAt: message.timestamp ?? defaultTimestamp, // CHA-M4k4
                         metadata: metadata,
                         headers: headers,
                         version: message.version ?? "", // CHA-M4k1
-                        timestamp: message.timestamp ?? Date(), // CHA-M4k4,
+                        timestamp: message.timestamp ?? defaultTimestamp, // CHA-M4k4,
                         operation: message.operation?.toChatOperation()
                     )
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e97430d and 4539d1a.

📒 Files selected for processing (8)
  • Sources/AblyChat/DefaultMessageReactions.swift (3 hunks)
  • Sources/AblyChat/DefaultMessages.swift (1 hunks)
  • Sources/AblyChat/DefaultRoomReactions.swift (1 hunks)
  • Sources/AblyChat/RoomReactionDTO.swift (3 hunks)
  • Tests/AblyChatTests/DefaultMessagesTests.swift (3 hunks)
  • Tests/AblyChatTests/DefaultRoomReactionsTests.swift (3 hunks)
  • Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (1 hunks)
  • Tests/AblyChatTests/RoomReactionDTOTests.swift (1 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Sources/AblyChat/DefaultRoomReactions.swift (10)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultOccupancy.swift:10-13
Timestamp: 2025-05-12T21:01:14.109Z
Learning: The `Occupancy` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultOccupancy` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/ContentView.swift:94-99
Timestamp: 2025-06-14T21:47:20.509Z
Learning: In the Ably Chat Swift example app, using fatalError for missing clientID is intentional and appropriate since it represents a programmer error rather than a recoverable runtime condition. The clientID is considered an essential configuration requirement.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Tests/AblyChatTests/RoomReactionDTOTests.swift (9)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/Mocks/MockRealtime.swift:348-384
Timestamp: 2025-06-14T16:19:29.327Z
Learning: The MockRealtime class in Example/AblyChatExample/Mocks/MockRealtime.swift is specifically for example app construction, not for testing. The actual test mocks are located in the Tests directory. If example app mocks are unused, fatalError calls are appropriate to catch accidental usage.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:28:19.696Z
Learning: The project uses Swift Testing framework with `#expect` macros for assertions, not XCTest framework with expectations and fulfillment.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (13)
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/Mocks/MockRealtime.swift:348-384
Timestamp: 2025-06-14T16:19:29.327Z
Learning: The MockRealtime class in Example/AblyChatExample/Mocks/MockRealtime.swift is specifically for example app construction, not for testing. The actual test mocks are located in the Tests directory. If example app mocks are unused, fatalError calls are appropriate to catch accidental usage.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription callbacks continue to work even when the handle is not stored, as the underlying services maintain their own storage of callbacks that remain registered until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription continues to work even if the handle is not stored, as the underlying services maintain references to the callbacks until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomReactions.swift:42-56
Timestamp: 2025-05-16T21:35:46.634Z
Learning: In the AblyChat framework, all subscription callbacks are annotated with @MainActor, ensuring they always execute on the main actor thread without requiring additional Task wrappers.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomLifecycleManager.swift:611-624
Timestamp: 2025-05-22T20:57:48.147Z
Learning: In AblyChat Swift, when using continuations with subscription callbacks, the continuation object is captured directly by the closure and doesn't depend on `self`. Even with `[weak self]` capture, the continuation will still be resumed properly.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultOccupancy.swift:66-69
Timestamp: 2025-05-12T21:02:25.928Z
Learning: SubscriptionHandle.unsubscribe is already marked with @MainActor annotation, so there's no need to wrap code in MainActor.run when calling it.
Sources/AblyChat/DefaultMessageReactions.swift (9)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:11-14
Timestamp: 2025-05-12T21:03:31.914Z
Learning: The `Typing` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultTyping` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultOccupancy.swift:10-13
Timestamp: 2025-05-12T21:01:14.109Z
Learning: The `Occupancy` protocol in the Ably Chat Swift SDK is annotated with `@MainActor`, making all conforming types like `DefaultOccupancy` automatically main actor-isolated without requiring explicit annotations on their methods.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Sources/AblyChat/DefaultMessages.swift (13)
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription callbacks continue to work even when the handle is not stored, as the underlying services maintain their own storage of callbacks that remain registered until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionHandleStorage.swift:37-40
Timestamp: 2025-05-12T21:02:28.274Z
Learning: In the AblyChat Swift codebase, the `SubscriptionHandle` struct has an `unsubscribe()` method for terminating subscriptions, not a `cancel()` method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription continues to work even if the handle is not stored, as the underlying services maintain references to the callbacks until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomLifecycleManager.swift:611-624
Timestamp: 2025-05-22T20:57:48.147Z
Learning: In AblyChat Swift, when using continuations with subscription callbacks, the continuation object is captured directly by the closure and doesn't depend on `self`. Even with `[weak self]` capture, the continuation will still be resumed properly.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomReactions.swift:42-56
Timestamp: 2025-05-16T21:35:46.634Z
Learning: In the AblyChat framework, all subscription callbacks are annotated with @MainActor, ensuring they always execute on the main actor thread without requiring additional Task wrappers.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Tests/AblyChatTests/DefaultRoomReactionsTests.swift (13)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/Mocks/MockRealtime.swift:348-384
Timestamp: 2025-06-14T16:19:29.327Z
Learning: The MockRealtime class in Example/AblyChatExample/Mocks/MockRealtime.swift is specifically for example app construction, not for testing. The actual test mocks are located in the Tests directory. If example app mocks are unused, fatalError calls are appropriate to catch accidental usage.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Sources/AblyChat/RoomReactionDTO.swift (4)
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Sources/AblyChat/Message.swift:163-175
Timestamp: 2025-06-14T21:58:57.802Z
Learning: In the AblyChat Swift SDK, the JSON key "reactions" is used for parsing reaction summaries in the Chat SDK layer, while "summary" is used in the ably-cocoa layer. Reactions can be sourced from either the realtime message's summary property or directly from the "reactions" dictionary in the JSON.
Learnt from: maratal
PR: ably/ably-chat-swift#165
File: Sources/AblyChat/Reaction.swift:14-14
Timestamp: 2024-12-10T01:59:02.065Z
Learning: For the 'ably-chat-swift' repository, documentation-only PRs should focus exclusively on public methods and properties. Avoid suggesting changes to internal comments or private methods in such PRs.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/MessageViews/MessageReactionsSheet.swift:15-31
Timestamp: 2025-06-14T16:18:47.038Z
Learning: In the AblyChat Swift SDK, there are three message reaction types: unique (one reaction per client per message), distinct (one reaction of each type per client per message), and multiple (any number of reactions including repeats, with counts). The MessageReactionsSheet specifically handles unique/distinct reactions where the count is always 1 per client per emoji. Only the "multiple" reaction type would have accumulating counts.
Tests/AblyChatTests/DefaultMessagesTests.swift (15)
Learnt from: maratal
PR: ably/ably-chat-swift#249
File: Tests/AblyChatTests/DefaultMessagesTests.swift:45-48
Timestamp: 2025-05-22T19:17:21.392Z
Learning: The `let doIt = {}` closures in DefaultMessagesTests.swift are temporary workarounds for compiler crashes (related to issue #233) and will be removed once Xcode 16.3 is released, so they should not be flagged for missing async/throws annotations.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionAsyncSequence.swift:36-41
Timestamp: 2025-06-29T16:02:43.988Z
Learning: In the AblyChat Swift codebase, the fatalError in SubscriptionAsyncSequence.swift's mock async sequence handling (around line 39) is intentional and should not be flagged. This fatalError catches programmer errors when a throwing AsyncSequence is incorrectly passed to the mock initializer, which is meant for testing/development purposes.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:20:38.904Z
Learning: In Swift tests using mock objects like MockRealtimeChannel, explicit subscription cleanup (via unsubscribe() or similar methods) is generally unnecessary since the mocks don't maintain real connections and will be garbage collected after the test completes.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/DefaultTyping.swift:131-138
Timestamp: 2025-05-12T21:04:36.263Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle closures should capture self weakly with `[weak self]` to avoid potential retain cycles, particularly when calling channel.unsubscribe() within the closure.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/SubscriptionHandleStorage.swift:37-40
Timestamp: 2025-05-12T21:02:28.274Z
Learning: In the AblyChat Swift codebase, the `SubscriptionHandle` struct has an `unsubscribe()` method for terminating subscriptions, not a `cancel()` method.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Tests/AblyChatTests/Mocks/MockRealtime.swift:41-47
Timestamp: 2025-06-14T15:18:17.427Z
Learning: In the MockRealtime class in Tests/AblyChatTests/Mocks/MockRealtime.swift, the body parameter in the request method is constrained to dictionary or array types, but currently only dictionary types are used. Arrays are not yet used for this method, so the current implementation assumes dictionary-only for simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/Mocks/MockRealtime.swift:348-384
Timestamp: 2025-06-14T16:19:29.327Z
Learning: The MockRealtime class in Example/AblyChatExample/Mocks/MockRealtime.swift is specifically for example app construction, not for testing. The actual test mocks are located in the Tests directory. If example app mocks are unused, fatalError calls are appropriate to catch accidental usage.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: In the ably-chat-swift project, MockRealtimeChannel processes messages synchronously when subscribe is called, immediately delivering the configured messages to the callback.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription callbacks continue to work even when the handle is not stored, as the underlying services maintain their own storage of callbacks that remain registered until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/ContentView.swift:203-209
Timestamp: 2025-05-12T21:11:08.937Z
Learning: In the AblyChat Swift codebase, SubscriptionHandle doesn't need to be retained/stored to keep subscriptions active. The subscription continues to work even if the handle is not stored, as the underlying services maintain references to the callbacks until explicitly unsubscribed via the handle's unsubscribe() method.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Sources/AblyChat/RoomLifecycleManager.swift:611-624
Timestamp: 2025-05-22T20:57:48.147Z
Learning: In AblyChat Swift, when using continuations with subscription callbacks, the continuation object is captured directly by the closure and doesn't depend on `self`. Even with `[weak self]` capture, the continuation will still be resumed properly.
Learnt from: maratal
PR: ably/ably-chat-swift#262
File: Tests/AblyChatTests/DefaultRoomReactionsTests.swift:0-0
Timestamp: 2025-05-23T16:29:39.712Z
Learning: The ably-chat-swift project uses Swift Testing framework (`#expect` macros) rather than XCTest for test assertions.
Learnt from: maratal
PR: ably/ably-chat-swift#286
File: Example/AblyChatExample/Mocks/MockClients.swift:0-0
Timestamp: 2025-05-16T21:04:26.244Z
Learning: In the ably-chat-swift project, mock implementations (like those in MockClients.swift) are intentionally kept simple, sometimes omitting parameter-based filtering behavior for testing simplicity.
Learnt from: maratal
PR: ably/ably-chat-swift#293
File: Example/AblyChatExample/ContentView.swift:94-99
Timestamp: 2025-06-14T21:47:20.509Z
Learning: In the Ably Chat Swift example app, using fatalError for missing clientID is intentional and appropriate since it represents a programmer error rather than a recoverable runtime condition. The clientID is considered an essential configuration requirement.
🧬 Code Graph Analysis (1)
Sources/AblyChat/RoomReactionDTO.swift (1)
Sources/AblyChat/JSONCodable.swift (2)
  • optionalStringValueForKey (145-159)
  • optionalObjectValueForKey (73-87)
🔇 Additional comments (19)
Tests/AblyChatTests/RoomReactionDTOTests.swift (1)

18-19: Test correctly reflects the new optional behavior.

The test update properly validates that RoomReactionDTO.Data can now be initialized with an empty dictionary, resulting in name == nil instead of throwing an error. This aligns with the validation loosening approach implemented in the related source files.

Sources/AblyChat/DefaultRoomReactions.swift (3)

75-75: Good fallback for missing clientId.

Using an empty string default for missing clientId allows the reaction to be processed while still indicating an unknown client. The spec reference CHA-ER4e3 confirms this is the intended behavior.


79-79: Appropriate fallback for missing reaction name.

Defaulting to an empty string when dto.name is nil ensures reactions can still be processed even with incomplete data. This aligns with the validation loosening approach and spec point CHA-ER4e1.


82-82: Reasonable timestamp fallback.

Using the current date as a fallback for missing timestamp is a sensible approach that maintains reaction processing while providing a meaningful default. The spec reference CHA-ER4e4 confirms this behavior.

Tests/AblyChatTests/Mocks/MockRealtimeChannel.swift (1)

149-149: Improved subscription tracking consistency.

Moving the subscription tracking outside the conditional ensures that subscriptions are always recorded, regardless of whether an immediate message is emitted. This improves test reliability and supports scenarios where both immediate and subsequent messages need to be handled consistently.

Sources/AblyChat/DefaultMessageReactions.swift (4)

87-87: Good documentation with spec reference.

Adding the CHA-MR6a1 comment clarifies the fallback behavior for missing summary JSON, improving code documentation.


112-112: Clear documentation of event type logic.

The CHA-MR7b1 comment helpfully documents the logic for determining reaction event types based on annotation actions.


113-113: Excellent improvement: graceful handling of unknown reaction types.

This change prevents reactions with unrecognized types from being silently discarded. Using .distinct as the default fallback is a reasonable choice that allows the reaction to be processed while maintaining expected behavior. This aligns well with the validation loosening approach.


126-126: Good documentation additions.

The CHA-MR7b3 comments improve code clarity by documenting the fallback behavior for missing client IDs and reaction names.

Also applies to: 133-133

Sources/AblyChat/RoomReactionDTO.swift (4)

7-7: Consistent optional name implementation.

Making the name property optional enables more permissive handling of reaction data, aligning with the overall validation loosening approach.


22-22: Proper interface update.

The computed property correctly reflects the optional nature of the underlying name field, maintaining consistency across the DTO interface.


44-44: Appropriate JSON decoding change.

Switching to optionalStringValueForKey correctly implements the optional name behavior, allowing JSON objects without the "name" key to be decoded successfully.


50-50: Good backward compatibility consideration.

Using name ?? "" ensures that nil names are serialized as empty strings, maintaining backward compatibility with systems expecting string values while supporting the new optional behavior.

Sources/AblyChat/DefaultMessages.swift (2)

85-86: Good change to handle unsupported actions gracefully

The switch from throwing errors to logging and returning aligns well with the PR's goal of making the code more tolerant. This prevents message processing from failing due to unsupported actions while maintaining observability through debug logging.


89-111: Well-structured handling of message data with appropriate defaults

The implementation correctly differentiates between delete and non-delete actions, providing empty values for deletes and safe defaults for other actions. The consistent use of default values (?? [:] and ?? "") ensures robustness when processing malformed messages.

Tests/AblyChatTests/DefaultRoomReactionsTests.swift (2)

35-72: Test updates correctly reflect the new reaction format

The changes properly update the test to use "name" instead of "type" for reactions, and the addition of the callback counter improves test reliability by verifying the expected number of invocations.


74-109: Important fix: Corrected event name for reaction simulation

Good catch on line 107 - using RoomReactionEvents.reaction.rawValue instead of a chat message event ensures the test correctly simulates a malformed reaction event. The callback counter addition and key rename maintain consistency with the new format.

Tests/AblyChatTests/DefaultMessagesTests.swift (2)

363-371: Good naming consistency improvement

The rename from subscriptionHandle to subscription improves readability and consistency with other tests.


380-441: Excellent test coverage for the new malformed event handling behavior

The updated test effectively validates that:

  1. Valid messages are processed correctly with all fields intact
  2. Malformed messages are still emitted but with sensible defaults (empty strings/dictionaries)

This aligns perfectly with the PR's goal of making the system more tolerant of incomplete data while maintaining observability.

@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 4539d1a to 7092f9a Compare July 14, 2025 17:00
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 17:01 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 7092f9a to 7c46c08 Compare July 14, 2025 17:05
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 14, 2025 17:07 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 7c46c08 to 32b50ae Compare July 18, 2025 13:31
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 18, 2025 13:33 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 32b50ae to 8e0e78c Compare July 18, 2025 13:38
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 18, 2025 13:39 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from 8e0e78c to af1c2f5 Compare July 18, 2025 13:41
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 18, 2025 13:42 Inactive
@maratal
maratal force-pushed the 321-soft-deletes-and-validation-loosening branch from af1c2f5 to eac37eb Compare July 18, 2025 13:47
@github-actions
github-actions Bot temporarily deployed to staging/pull/330/AblyChat July 18, 2025 13:48 Inactive
@maratal maratal changed the title Add the soft delete behaviour and validation loosening [ECO-5438] Add the soft delete behaviour and validation loosening Jul 18, 2025

@umair-ably umair-ably left a comment

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.

lgtm

@maratal
maratal merged commit eee4426 into main Jul 22, 2025
41 checks passed
@maratal
maratal deleted the 321-soft-deletes-and-validation-loosening branch July 22, 2025 23:22
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.

Soft deletes changes

2 participants