Conversation
|
Warning This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
How to use the Graphite Merge QueueAdd the label mergequeue to this PR to add it to the merge queue. You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
|
Claude finished @mchenani's task —— View job Code Review CompleteReview Date: March 17, 2026, 22:31 UTC
Critical Issues (Already Identified by Macroscope)The two issues flagged by Macroscope are blocking and must be fixed:
Additional Issues Found1. Inconsistent null handling between platformsAndroid (EditMessageCodec.kt:45): compression = encoded.compression?.let { it.number }Encodes compression, but the decode at line 82 has the NPE issue Macroscope found. iOS (EditMessageCodec.swift:69): compression: encoded.hasCompression ? Int32(encoded.compression.rawValue) : nilEncodes compression, but decode (lines 81-101) completely drops it. Both codecs fail to properly round-trip the compression field, but for different reasons. 2. Test gap: No compression testingNeither platform's tests verify that
Recommendation: Add test cases that encode content with compression (GZIP/DEFLATE) inside 3. Android: Potential issue with
|
c42d6ba to
d666e51
Compare
| } | ||
| putAllParameters(ffiContent.parameters) | ||
| ffiContent.fallback?.let { setFallback(it) } | ||
| ffiContent.compression?.let { setCompression(Content.Compression.forNumber(it)) } |
There was a problem hiding this comment.
🟠 High codecs/EditMessageCodec.kt:82
Content.Compression.forNumber(it) returns null for unrecognized compression values, which is passed directly to setCompression(). This throws NullPointerException when the FFI layer returns an unknown compression number. Consider using ?.let to handle the null case.
- ffiContent.compression?.let { setCompression(Content.Compression.forNumber(it)) }
+ ffiContent.compression?.let { Content.Compression.forNumber(it)?.let { setCompression(it) } }🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file sdks/android/library/src/main/java/org/xmtp/android/library/codecs/EditMessageCodec.kt around line 82:
`Content.Compression.forNumber(it)` returns `null` for unrecognized compression values, which is passed directly to `setCompression()`. This throws `NullPointerException` when the FFI layer returns an unknown compression number. Consider using `?.let` to handle the null case.
Evidence trail:
sdks/android/library/src/main/java/org/xmtp/android/library/codecs/EditMessageCodec.kt line 82 shows `ffiContent.compression?.let { setCompression(Content.Compression.forNumber(it)) }`. The `?.let` only guards against null `ffiContent.compression`, but `Content.Compression.forNumber(it)` can return null for unrecognized enum values (standard protobuf behavior), which would be passed directly to `setCompression()` causing NPE.
| return try EncodedContent(serializedBytes: encodeEditMessage(request: ffi)) | ||
| } | ||
|
|
||
| public func decode(content: EncodedContent) throws -> EditMessageRequest { |
There was a problem hiding this comment.
🟠 High Codecs/EditMessageCodec.swift:81
The decode method drops the compression field when reconstructing EncodedContent from ffiContent. encode passes compression to FfiEncodedContent, but decode never reads ffiContent.compression back into the result. This causes editedContent.hasCompression to be false after round-tripping, so subsequent calls to decompressContent() will skip decompression and return the raw compressed bytes instead of the decompressed content.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
In file sdks/ios/Sources/XMTPiOS/Codecs/EditMessageCodec.swift around line 81:
The `decode` method drops the `compression` field when reconstructing `EncodedContent` from `ffiContent`. `encode` passes `compression` to `FfiEncodedContent`, but `decode` never reads `ffiContent.compression` back into the result. This causes `editedContent.hasCompression` to be false after round-tripping, so subsequent calls to `decompressContent()` will skip decompression and return the raw compressed bytes instead of the decompressed content.
Evidence trail:
sdks/ios/Sources/XMTPiOS/Codecs/EditMessageCodec.swift:
- Line 69: `compression: encoded.hasCompression ? Int32(encoded.compression.rawValue) : nil,` (encode passes compression)
- Lines 81-101: decode method reconstructs EncodedContent but never reads ffiContent.compression
sdks/ios/Sources/XMTPiOS/Codecs/ContentCodec.swift:
- Lines 21-23: `if hasCompression { encodedContent = try decompressContent() }`
- Lines 52-54: `func decompressContent() throws -> EncodedContent { if !hasCompression { return self }`
The missing compression assignment in decode means hasCompression will be false, causing decompressContent to be skipped.
ApprovabilityVerdict: Needs human review Diff is too large for automated approval analysis. A human reviewer should evaluate this PR. You can customize Macroscope's approvability policy. Learn more. |

Add edit message support to mobile and WASM SDKs
editMessageanddeleteMessagemethods toFfiConversation(mobile), NodeConversation, and WASMConversation, returning event IDs.streamMessageEditstoFfiConversations(mobile), NodeConversations, and WASMConversations, streaming edited messages via a callback.FfiDecodedMessageandDecodedMessagenow includeeditedAtNsandisEditedfields; thecontentgetter returns edited content when present, preserving reply threading semantics.EditMessageCodecandEditMessageRequestfor iOS and Android, encoding/decodingxmtp.org/editMessage v1.0content; codec produces no fallback string and does not request push delivery.contenton previously-received decoded messages now returns edited content rather than original content if an edit is present, which is a behavioral change for existing consumers.Macroscope summarized d666e51.