Skip to content

Conversation

@debdutdeb
Copy link
Member

@debdutdeb debdutdeb commented Sep 26, 2025

Proposed changes (including videos or screenshots)

Issue(s)

Steps to test or reproduce

Further comments

FDR-165

RocketChat/homeserver#231

Summary by CodeRabbit

  • New Features

    • Better support for rich replies in Matrix, showing quoted context correctly.
  • Bug Fixes

    • Improved detection of thread messages to identify thread roots and replies more accurately.
    • More reliable handling of edited messages to avoid missed or incorrect edit states.
  • Stability

    • Improved error logging to aid diagnosis and reduce unexpected failures.
  • Chores

    • Upgraded federation SDK dependency to v0.1.10.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Sep 26, 2025

Looks like this PR is not ready to merge, because of the following issues:

  • This PR is missing the 'stat: QA assured' label

Please fix the issues and try again

If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Sep 26, 2025

⚠️ No Changeset found

Latest commit: 6f630d7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 26, 2025

Walkthrough

Refactors Matrix message relation handling to explicitly guard relation presence, distinguish threads, rich replies, and edits, extract quote/thread IDs accordingly, and adjust error logging argument order; also bumps @rocket.chat/federation-sdk from 0.1.9 to 0.1.10 in two EE package.json files.

Changes

Cohort / File(s) Summary of Changes
Matrix relation & message handling
ee/packages/federation-matrix/src/events/message.ts
Adds hasRelation guard; determines isThreadMessage only when relation.rel_type === 'm.thread'; introduces isRichReply using relation['m.in_reply_to']; computes threadRootEventId and quoteMessageEventId from relation fields; refactors edit detection to use hasRelation && relation.rel_type === 'm.replace' and relation.event_id; updates control flow for edits and rich replies; adds SPEC-style comments.
Dependency bumps
ee/apps/federation-service/package.json, ee/packages/federation-matrix/package.json
Bumps @rocket.chat/federation-sdk from 0.1.9 to 0.1.10.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant MX as Matrix Event
  participant H as Message Handler
  participant Logger as Logger

  MX->>H: receive message event (content)
  alt content has `m.relates_to`
    H->>H: set hasRelation = true
    alt relation.rel_type == "m.thread"
      H->>H: mark as thread message\nextract threadRootEventId
    else relation.rel_type == "m.replace"
      H->>H: mark as edit\nuse relation.event_id to find original
    else
      H->>H: other relation types (no thread/edit)
    end
  else no `m.relates_to`
    alt content has `m.in_reply_to`
      H->>H: mark as rich reply\nextract quoteMessageEventId
    else
      H->>H: regular message
    end
  end

  H-->>MX: proceed with mapped metadata (thread/quote/edit)
  opt on error
    H->>Logger: logger.error(error, "Error processing Matrix message:")
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

stat: ready to merge, stat: QA assured

Suggested reviewers

  • ricardogarim

Poem

A twitch, a hop, a relation's clue,
Threads and quotes I now construe.
Edits find home, replies shine bright,
Logs flipped kindly in the night.
Rabbit cheers—messages set right. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning Alongside the thread versus quote fix, the PR includes version bumps for @rocket.chat/federation-sdk in two package.json files which are not referenced in the FDR-165 objectives and appear unrelated to correcting thread message rendering. Separate or justify the dependency version bumps in a dedicated PR or include a comment explaining their necessity for this fix.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title succinctly describes the central change, namely correcting how thread messages are misidentified as quotes in the native-federation code, and it directly aligns with the modifications to relation handling in message.ts without extraneous wording.
Linked Issues Check ✅ Passed The changes introduce explicit relation existence checks and distinct handling for m.thread versus m.in_reply_to relations to ensure thread messages are rendered correctly instead of as quotes, directly fulfilling the FDR-165 objective to fix thread message display from Synapse.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/fdr165

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.

Copy link
Contributor

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7a0d52f and 6f630d7.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (3)
  • ee/apps/federation-service/package.json (1 hunks)
  • ee/packages/federation-matrix/package.json (1 hunks)
  • ee/packages/federation-matrix/src/events/message.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
ee/packages/federation-matrix/src/events/message.ts (1)
packages/core-typings/src/IMessage/IMessage.ts (2)
  • isThreadMessage (317-317)
  • isEditedMessage (264-271)
⏰ 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). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

Comment on lines +140 to 156
const hasRelation = relation && 'rel_type' in relation;

const isThreadMessage = hasRelation && relation.rel_type === 'm.thread';

const threadRootEventId = isThreadMessage && relation.event_id;

const quoteMessageEventId = relation && 'm.in_reply_to' in relation && relation['m.in_reply_to']?.event_id;
// SPEC: Though rich replies form a relationship to another event, they do not use rel_type to create this relationship.
// Instead, a subkey named m.in_reply_to is used to describe the reply’s relationship,
const isRichReply = relation && !('rel_type' in relation) && 'm.in_reply_to' in relation;

const quoteMessageEventId = isRichReply && relation['m.in_reply_to']?.event_id;

const thread = threadRootEventId ? await getThreadMessageId(threadRootEventId) : undefined;

const isEditedMessage = relation?.rel_type === 'm.replace';
if (isEditedMessage && relation?.event_id && data.content['m.new_content']) {
const isEditedMessage = hasRelation && relation.rel_type === 'm.replace';
if (isEditedMessage && relation.event_id && data.content['m.new_content']) {
logger.debug('Received edited message from Matrix, updating existing message');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore quote detection when rel_type is present on replies.

Element and other Matrix homeservers routinely send rich replies with m.relates_to.rel_type = "m.reference" (per MSC2677). By requiring the property to be absent (!('rel_type' in relation)), we now skip quote handling for those events, so legitimate replies regress to plain messages. Please loosen the guard to treat replies as quotes whenever m.in_reply_to exists, except for the explicit thread/edit types.

-	const hasRelation = relation && 'rel_type' in relation;
-
-	const isThreadMessage = hasRelation && relation.rel_type === 'm.thread';
+	const hasRelation = relation && 'rel_type' in relation;
+	const relationRelType = hasRelation ? relation.rel_type : undefined;
+
+	const isThreadMessage = relationRelType === 'm.thread';
@@
-	const isRichReply = relation && !('rel_type' in relation) && 'm.in_reply_to' in relation;
+	const isRichReply =
+		!!relation &&
+		'm.in_reply_to' in relation &&
+		relationRelType !== 'm.thread' &&
+		relationRelType !== 'm.replace';
@@
-	const isEditedMessage = hasRelation && relation.rel_type === 'm.replace';
+	const isEditedMessage = relationRelType === 'm.replace';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hasRelation = relation && 'rel_type' in relation;
const isThreadMessage = hasRelation && relation.rel_type === 'm.thread';
const threadRootEventId = isThreadMessage && relation.event_id;
const quoteMessageEventId = relation && 'm.in_reply_to' in relation && relation['m.in_reply_to']?.event_id;
// SPEC: Though rich replies form a relationship to another event, they do not use rel_type to create this relationship.
// Instead, a subkey named m.in_reply_to is used to describe the reply’s relationship,
const isRichReply = relation && !('rel_type' in relation) && 'm.in_reply_to' in relation;
const quoteMessageEventId = isRichReply && relation['m.in_reply_to']?.event_id;
const thread = threadRootEventId ? await getThreadMessageId(threadRootEventId) : undefined;
const isEditedMessage = relation?.rel_type === 'm.replace';
if (isEditedMessage && relation?.event_id && data.content['m.new_content']) {
const isEditedMessage = hasRelation && relation.rel_type === 'm.replace';
if (isEditedMessage && relation.event_id && data.content['m.new_content']) {
logger.debug('Received edited message from Matrix, updating existing message');
const hasRelation = relation && 'rel_type' in relation;
const relationRelType = hasRelation ? relation.rel_type : undefined;
const isThreadMessage = relationRelType === 'm.thread';
const threadRootEventId = isThreadMessage && relation.event_id;
// SPEC: Though rich replies form a relationship to another event, they do not use rel_type to create this relationship.
// Instead, a subkey named m.in_reply_to is used to describe the reply’s relationship,
const isRichReply =
!!relation &&
'm.in_reply_to' in relation &&
relationRelType !== 'm.thread' &&
relationRelType !== 'm.replace';
const quoteMessageEventId = isRichReply && relation['m.in_reply_to']?.event_id;
const thread = threadRootEventId ? await getThreadMessageId(threadRootEventId) : undefined;
const isEditedMessage = relationRelType === 'm.replace';
if (isEditedMessage && relation.event_id && data.content['m.new_content']) {
logger.debug('Received edited message from Matrix, updating existing message');
🤖 Prompt for AI Agents
In ee/packages/federation-matrix/src/events/message.ts around lines 140 to 156,
the current check treats a reply as a rich reply only when rel_type is absent,
which skips quote handling for replies that include rel_type (e.g.
"m.reference"); update the logic so that a reply is considered a rich reply
whenever relation['m.in_reply_to'] exists (and relation is defined), but still
exclude events that are explicit threads (rel_type === 'm.thread') or edits
(rel_type === 'm.replace'). Concretely, compute hasRelation safely, keep
isThreadMessage and isEditedMessage as-is, then set isRichReply = relation &&
relation['m.in_reply_to'] && !isThreadMessage && !isEditedMessage so
quoteMessageEventId is derived when m.in_reply_to.event_id exists; ensure
threadRootEventId and edits remain unaffected.

@codecov
Copy link

codecov bot commented Sep 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 67.40%. Comparing base (f1fbcdd) to head (6f630d7).
⚠️ Report is 1 commits behind head on develop.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop   #37077      +/-   ##
===========================================
+ Coverage    67.39%   67.40%   +0.01%     
===========================================
  Files         3328     3328              
  Lines       113342   113342              
  Branches     20563    20565       +2     
===========================================
+ Hits         76386    76401      +15     
+ Misses       34356    34338      -18     
- Partials      2600     2603       +3     
Flag Coverage Δ
e2e 57.29% <ø> (+0.01%) ⬆️
unit 71.17% <ø> (+0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

3 participants