Skip to content

MatrixRTC: Support the optional leave_reason in rtc membership content - #5437

Open
BillCarsonFr wants to merge 13 commits into
developfrom
valere/rtc/leave_reason
Open

MatrixRTC: Support the optional leave_reason in rtc membership content#5437
BillCarsonFr wants to merge 13 commits into
developfrom
valere/rtc/leave_reason

Conversation

@BillCarsonFr

Copy link
Copy Markdown
Member

Adds support for leave_reason as per MSC4143

Breaking change:

  • Leave event has now a leave_reason optional key instead of enpty
  • Previously for leaving the membership manager was just firing the scheduled leave, now we are cancelling it, then we send a proper leave event with the reason

Checklist

  • Tests written for new code (and old code if feasible).
  • New or updated public/exported symbols have accurate TSDoc documentation.
  • Linter and other CI checks pass.
  • Sign-off given on the changes (see CONTRIBUTING.md).

@Johennes Johennes 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.

Overall looks good. Just some details.

Comment thread src/matrixrtc/MembershipManager.ts Outdated
Comment thread src/matrixrtc/MembershipManager.ts Outdated
Comment thread src/matrixrtc/types.ts
Comment thread src/matrixrtc/MembershipManagerActionScheduler.ts

Copilot AI 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.

Pull request overview

This PR adds MSC4143 leave_reason support to MatrixRTC membership leave flows, propagating an optional structured leave reason through the public session API and membership manager, and updating event typings and unit tests accordingly.

Changes:

  • Introduces LeaveReason / leave_reason types and constants, and includes leave_reason in leave and delayed-leave event content.
  • Updates the membership action scheduler/manager to send an explicit leave event (optionally with reason) and cancel any scheduled delayed leave.
  • Extends event type mappings and updates unit tests to validate the new leave behavior.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/matrixrtc/types.ts Adds LeaveReason types/constants and leave event content shape.
src/matrixrtc/MembershipManagerActionScheduler.ts Threads leave-reason action data through the scheduler and triggers cancel+leave actions.
src/matrixrtc/MembershipManager.ts Implements sending { leave_reason }, cancels scheduled delayed leave, and updates action/data plumbing.
src/matrixrtc/MatrixRTCSession.ts Exposes leaveReason through leaveRoomSession and filters leave-only events.
src/matrixrtc/index.ts Re-exports selected leave-reason constants from the public entrypoint.
src/matrixrtc/IMembershipManager.ts Extends the public leave() API with an optional leave reason.
src/@types/event.ts Updates event content typings to permit leave_reason.
spec/unit/matrixrtc/MembershipManager.spec.ts Updates/adds tests for cancel + explicit leave event behavior and content.
Comments suppressed due to low confidence (1)

src/matrixrtc/types.ts:248

  • The LEAVE_REASON_DELAYED constant uses code "delayed_leaved", but MSC4143 specifies the generic code as "delayed_leave". This should match the LeaveCode union and the spec value for wire compatibility.
export const LEAVE_REASON_DELAYED: LeaveReason = {
    code: "delayed_leaved",
    reason: "The user was removed due to inactivity (no heartbeat received).",

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/matrixrtc/types.ts Outdated
Comment thread src/matrixrtc/MembershipManager.ts Outdated
Comment thread src/matrixrtc/MembershipManager.ts Outdated
Comment thread src/matrixrtc/MatrixRTCSession.ts
Comment thread src/@types/event.ts Outdated
Comment thread src/matrixrtc/index.ts

@dbkr dbkr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Mostly looks fine but you've said 'feat' in the PR title but 'task' in the label. It sounds like an enhancement (we use the labels instead of conventional commits because our PR titles go in the changelog).

Comment thread src/matrixrtc/types.ts
Comment thread src/matrixrtc/MembershipManagerActionScheduler.ts Outdated
Comment thread src/matrixrtc/MatrixRTCSession.ts Outdated
@BillCarsonFr BillCarsonFr added T-Enhancement and removed T-Task Tasks for the team like planning labels Jul 30, 2026
@BillCarsonFr BillCarsonFr changed the title feat(rtc): Add support for leave_reason in rtc membership MatrixRTC: Support the optional leave_reason in rtc membership content Jul 30, 2026
@BillCarsonFr
BillCarsonFr requested a review from dbkr July 30, 2026 13:35
Comment thread src/matrixrtc/types.ts
/** The member left intentionally (e.g. by hanging up a call) */
export const LEAVE_REASON_HANGUP: LeaveReason = {
code: "leave",
reason: "The member left intentionally (e.g. by hanging up a call).",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It feels a little funny to have a user-facing string that's nonspecific about the type of application. I would rather omit the reasons in this file and (ideally) instead have them passed to the membership manager by the application's code.

Comment thread src/@types/event.ts
[M_POLL_START.name]: PollStartEventContent;
[M_POLL_END.name]: PollEndEventContent;
[EventType.RTCMembership]: RtcMembershipData | { msc4354_sticky_key: string }; // An object containing just the sticky key is empty.
[EventType.RTCMembership]: RtcMembershipData | { msc4354_sticky_key: string; leave_reason?: LeaveReason };

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Shouldn't there be more properties in this variant, like slot_id and member?

Comment thread src/@types/event.ts
| SessionMembershipData
| LeaveMembershipEventContent
| EmptyObject;
[EventType.RTCMembership]: RtcMembershipData | EmptyObject;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

By the way, should this state event type still exist? (If so, should it also get a LeaveMembershipEventContent variant?)

Comment thread src/@types/event.ts
Comment on lines +404 to +405
| LeaveMembershipEventContent
| EmptyObject;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The EmptyObject variant is redundant to the LeaveMembershipEventContent variant, since that interface also admits an empty object

const eventKeysCount = Object.keys(content).filter((k) => k !== "msc4354_sticky_key").length;
// Don't even bother about empty events (saves us from costly type/"key in" checks in bigger rooms)
if (eventKeysCount === 0) return false;
if (eventKeysCount === 0 || (eventKeysCount === 1 && "leave_reason" in content)) return false;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
if (eventKeysCount === 0 || (eventKeysCount === 1 && "leave_reason" in content)) return false;
if (eventKeysCount === 0 || "leave_reason" in content) return false;

To account for the other keys that can be part of a leave membership (slot_id etc.)

/**
* Additional parameters of the action
*/
data?: MembershipActionData[MembershipActionType];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
data?: MembershipActionData[MembershipActionType];
data: MembershipActionData[MembershipActionType];

Seems reasonable to require the data when it's specified for an action type

Comment on lines +146 to +156
replace: [
{
ts: Date.now(),
type: MembershipActionType.SendLeaveEvent,
data: leaveReason ? { leaveReason } : undefined,
},
{
ts: Date.now(),
type: MembershipActionType.CancelledScheduledDelayedLeaveEvent,
},
],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I am glad to see that this is sending the leave event before canceling, since that's presumably a better way of dealing with the lack of atomicity in this operation. But ideally, the membership manager would only cancel the delayed event in step 2 if it actually succeeds at sending the leave event in step 1. Do you see any way to make the machine do that?

this.clientWithSticky._unstable_sendStickyDelayedEvent(
protected clientSendDelayedDisconnectMembership: () => Promise<SendDelayedEventResponse> = () => {
this.logger.debug(
`StickyMembershipManager send delayed disconnect membership event memberId: ${this.memberId}`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
`StickyMembershipManager send delayed disconnect membership event memberId: ${this.memberId}`,
`send delayed disconnect membership event memberId: ${this.memberId}`,

(It's already prefixed)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants