Skip to content

feat(send_queue): send redactions via the send queue#6250

Open
Johennes wants to merge 13 commits intomatrix-org:mainfrom
Johennes:johannes/send-queue-redactions
Open

feat(send_queue): send redactions via the send queue#6250
Johennes wants to merge 13 commits intomatrix-org:mainfrom
Johennes:johannes/send-queue-redactions

Conversation

@Johennes
Copy link
Contributor

@Johennes Johennes commented Mar 5, 2026

This is a first step towards #4162 and adds a way to send redactions (including their local echoes) via the send queue.

I had to introduce new variants for SentRequestKey and LocalEchoContent because in some room versions the redacted event ID sits at the top-level of the event rather than in content.

At the timeline level redactions are handled via a new boolean flag in AggregationKind::Redaction. Local echoes of redactions merely set a flag on the timeline event whereas remote echoes of redactions lead to actual redactions as before.

The FFI bindings will be updated in a follow-up PR.

  • I've documented the public API Changes in the appropriate CHANGELOG.md files.
  • This PR was made with the help of AI.

@Johennes Johennes force-pushed the johannes/send-queue-redactions branch 2 times, most recently from 48f5ec6 to 01a4c00 Compare March 5, 2026 15:43
@codecov
Copy link

codecov bot commented Mar 5, 2026

Codecov Report

❌ Patch coverage is 69.77778% with 68 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.78%. Comparing base (39255c0) to head (44bc666).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
crates/matrix-sdk/src/send_queue/mod.rs 56.33% 29 Missing and 2 partials ⚠️
...rates/matrix-sdk-ui/src/timeline/controller/mod.rs 58.82% 14 Missing ⚠️
...rates/matrix-sdk-ui/src/timeline/event_item/mod.rs 31.57% 13 Missing ⚠️
...rix-sdk-ui/src/timeline/controller/aggregations.rs 56.25% 7 Missing ⚠️
crates/matrix-sdk-base/src/store/send_queue.rs 33.33% 1 Missing and 1 partial ⚠️
...trix-sdk/src/latest_events/latest_event/builder.rs 98.70% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6250      +/-   ##
==========================================
- Coverage   89.80%   89.78%   -0.02%     
==========================================
  Files         376      376              
  Lines      102634   102849     +215     
  Branches   102634   102849     +215     
==========================================
+ Hits        92166    92348     +182     
- Misses       6882     6923      +41     
+ Partials     3586     3578       -8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 5, 2026

Merging this PR will not alter performance

✅ 50 untouched benchmarks


Comparing Johennes:johannes/send-queue-redactions (44bc666) with main (39255c0)

Open in CodSpeed

@Johennes
Copy link
Contributor Author

Sorry for the ping @bnjbvr. 🙈 Since we briefly spoke about this in the dev room, I was curious if you had any high-level thoughts on this change? I'm basically just trying to verify that this is moving into the right direction architecturally before spending more time on it. Any thoughts on this would be highly appreciated.

@bnjbvr bnjbvr self-requested a review March 10, 2026 10:04
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks for the ping. Proposed a slightly different implementation at the timeline level, so that users don't have to check two booleans to know if something's been redacted. Looks like you're on the right track, though!

@Johennes Johennes force-pushed the johannes/send-queue-redactions branch 3 times, most recently from 76726b6 to 0ceef26 Compare March 14, 2026 18:48
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
@Johennes Johennes force-pushed the johannes/send-queue-redactions branch from 0ceef26 to ba8f1bb Compare March 14, 2026 18:54
@Johennes
Copy link
Contributor Author

Thanks for the initial feedback. I think this is now ready for review. I've included sending redactions in the send queue and handling their local echoes in the timeline in two separate commits. There will have to be a follow-up PR to change the entry paths in the FFI and UI layer to actually use the send queue when sending redactions. I thought it might be good to exclude this here.

@Johennes Johennes marked this pull request as ready for review March 14, 2026 19:00
@Johennes Johennes requested a review from a team as a code owner March 14, 2026 19:00
@Johennes Johennes requested review from bnjbvr and stefanceriu and removed request for a team March 14, 2026 19:00
@stefanceriu stefanceriu removed their request for review March 16, 2026 07:15
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks, makes sense to me to keep this PR as minimal as possible, considering it's already 600LOC; thanks for thinking about this! I've posted a comment which might be more a question/a thing to double-check, with respect to the shape of the saved event in the DB (might be different based on the room version). Let me know if I'm completely wrong here :)

Inline is_local_redacted

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Remove unredacted_content ctor parameter

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Switch from then_some to then to make the operation lazy

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Add documentation for the unredact method

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Regroup match arms

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Use a room-version specific format when caching local redaction events

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
@Johennes Johennes requested a review from bnjbvr March 18, 2026 13:58
Copy link
Member

@bnjbvr bnjbvr left a comment

Choose a reason for hiding this comment

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

Thanks! Sorry, I spotted a few more things, including one non-trivial question that might turn into an interesting experiment…

content = if content_field_redacts { format!("\"redacts\":\"{redacts}\",{reason}") } else { reason }
),
) {
Ok(event) => Some(TimelineEvent::from_plaintext(event)),
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to also do the little encryption dance, if the room was encrypted? I think redaction events can be encrypted, so we likely need to…

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I think the redaction event itself is always unencrypted. The SDK doesn't actually send it like a normal event. It calls PUT /_matrix/client/v3/rooms/{roomId}/redact/{eventId}/{txnId} and then the server inserts the actual event.

error: Arc::new(matrix_sdk::Error::SendQueueWedgeError(Box::new(
send_error,
))),
is_recoverable: false,
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this bool be based on a field of send_error somehow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, I think not. This is actually copied from the LocalEchoContent::Event match-arm a few lines above. It seems that send_error is of type QueueWedgeError which appears to always be unrecoverable.

/// Represents a failed to send unrecoverable error of an event sent via the
/// send queue.

Comment on lines +84 to +87
/// If a redaction for this event is currently being sent but the server
/// hasn't yet acknowledged it via its remote echo, the original content
/// before redaction. Otherwise, None.
pub(super) unredacted_content: Option<TimelineItemContent>,
Copy link
Member

Choose a reason for hiding this comment

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

I realize I forgot to ask the previous time, but could we store the unredacted_content in MsgLikeKind::Redacted, or would it make the code super hard to read, or expose an internal implementation detail to the consumers of these APIs? I think it would be nice in that it would make it impossible to represent impossible states, but maybe it complicates things a bit too much, WDYT?

Copy link
Contributor Author

@Johennes Johennes Mar 20, 2026

Choose a reason for hiding this comment

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

Hm, I'm probably entirely misunderstanding but does unredacted_content not necessarily need to hold just a normal TimelineItemContent with any MsgLikeKind because we want to be able to restore the original content upon unredaction?

Copy link
Contributor Author

@Johennes Johennes Mar 20, 2026

Choose a reason for hiding this comment

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

Or wait, you mean move unredacted_content from here into MsgLikeKind::Redacted? But then we'd have a TimelineItemContent inside of MsgLikeKind?

Sorry, I'm most likely just being dense. 🙈

Lazily allocate string

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Extract bindings to simplify format statement

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Fix line breaks in comments

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants