fix(sync): resolve $ME and $LAZY state keys in sliding sync required_state #1690

Open
Reaster wants to merge 2 commits from Reaster/continuwuity:Sync--$ME-and-$LAZY into main
First-time contributor

Summary

collect_required_state in src/api/client/sync/v5.rs currently only
expands the * wildcard when building a sliding sync response. The
$ME and $LAZY sentinel values defined by MSC3575 are passed
through as literal state keys, so the subsequent room_state_get
lookups always miss.

This breaks clients built on the Matrix Rust SDK (most notably
Element X iOS / Android), which rely on $ME to fetch the current
user's push rules during sync. When the lookup fails the client falls
back to silent notifications.

Closes #1661. Related: #1533, #1424,
element-hq/element-x-ios#5132.

Changes

  • collect_required_state now also takes sender_user and the
    room's timeline_pdus.
  • $ME → replaced by sender_user.as_str() before the state lookup.
  • $LAZY (only meaningful for m.room.member) → expanded to the
    member events of every user that sent a timeline event plus the
    target of every m.room.member event in the timeline, matching the
    behaviour of Synapse and Tuwunel.
  • The literal "$LAZY" key is no longer looked up directly; it would
    always return Err.
  • A small fetched set de-duplicates events so an explicit member
    key combined with $LAZY, or with an earlier * expansion, does
    not push the same event twice.
  • $LAZY is skipped when m.room.member has already been wildcard-
    expanded in the same request.

The control flow was reshaped from if / else if to a match on the
state key for readability, but the * branch and the default branch
behave exactly as before.

Non-goals

  • The lazy_members: true boolean from the RoomSubscription schema
    is still not implemented. Only the $LAZY sentinel in
    required_state is handled here. Left for a follow-up.

Testing

  • Local build via docker compose build conduwuit against the
    bundled Dockerfile.
  • Manually verified with Element X iOS that push rules are now
    delivered on initial sync and that notifications produce sound /
    vibration again.
  • Existing sliding sync flows (wildcard expansion, explicit state
    keys) are unchanged — covered by the existing Complement suite.

Reference

The resolution logic mirrors Tuwunel's
src/api/client/sync/v5/rooms.rs (lines ~150-260),
adapted to continuwuity's non-stream loop style.

Changelog entry — add file changelog.d/<PR_NUMBER>.bugfix (replace number after MR created):

Resolve $ME and $LAZY sentinels in sliding sync required_state, fixing push-rule loading for Element X and other Matrix Rust SDK
clients.

## Summary `collect_required_state` in `src/api/client/sync/v5.rs` currently only expands the `*` wildcard when building a sliding sync response. The `$ME` and `$LAZY` sentinel values defined by [MSC3575] are passed through as literal state keys, so the subsequent `room_state_get` lookups always miss. This breaks clients built on the Matrix Rust SDK (most notably Element X iOS / Android), which rely on `$ME` to fetch the current user's push rules during sync. When the lookup fails the client falls back to silent notifications. Closes #1661. Related: #1533, #1424, element-hq/element-x-ios#5132. ## Changes - `collect_required_state` now also takes `sender_user` and the room's `timeline_pdus`. - `$ME` → replaced by `sender_user.as_str()` before the state lookup. - `$LAZY` (only meaningful for `m.room.member`) → expanded to the member events of every user that sent a timeline event plus the target of every `m.room.member` event in the timeline, matching the behaviour of Synapse and Tuwunel. - The literal `"$LAZY"` key is no longer looked up directly; it would always return `Err`. - A small `fetched` set de-duplicates events so an explicit member key combined with `$LAZY`, or with an earlier `*` expansion, does not push the same event twice. - `$LAZY` is skipped when `m.room.member` has already been wildcard- expanded in the same request. The control flow was reshaped from `if / else if` to a `match` on the state key for readability, but the `*` branch and the default branch behave exactly as before. ## Non-goals - The `lazy_members: true` boolean from the `RoomSubscription` schema is still not implemented. Only the `$LAZY` sentinel in `required_state` is handled here. Left for a follow-up. ## Testing - Local build via `docker compose build conduwuit` against the bundled Dockerfile. - Manually verified with Element X iOS that push rules are now delivered on initial sync and that notifications produce sound / vibration again. - Existing sliding sync flows (wildcard expansion, explicit state keys) are unchanged — covered by the existing Complement suite. ## Reference The resolution logic mirrors Tuwunel's [`src/api/client/sync/v5/rooms.rs`][tuwunel] (lines ~150-260), adapted to continuwuity's non-stream loop style. [MSC3575]: https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/3575-sync.md [tuwunel]: https://github.com/matrix-construct/tuwunel/blob/main/src/api/client/sync/v5/rooms.rs Changelog entry — add file changelog.d/<PR_NUMBER>.bugfix (replace number after MR created): Resolve `$ME` and `$LAZY` sentinels in sliding sync `required_state`, fixing push-rule loading for Element X and other Matrix Rust SDK clients.
fix(sync): resolve $ME and $LAZY state keys in sliding sync required_state
Some checks failed
Documentation / Build and Deploy Documentation (pull_request) Blocked by required conditions
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Checks / Changelog / Check changelog is added (pull_request_target) Failing after 8s
Auto Labeler / Apply labels based on changed files (pull_request_target) Successful in 25s
ff91de6a76
add changelog
Some checks are pending
Documentation / Build and Deploy Documentation (pull_request) Blocked by required conditions
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 30s
a0e4efe1d1
Reaster force-pushed Sync--$ME-and-$LAZY from a0e4efe1d1
Some checks are pending
Documentation / Build and Deploy Documentation (pull_request) Blocked by required conditions
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 30s
to 5b6d65b87c
Some checks are pending
Documentation / Build and Deploy Documentation (pull_request) Blocked by required conditions
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 8s
2026-04-21 09:57:48 +00:00
Compare
Some checks are pending
Documentation / Build and Deploy Documentation (pull_request) Blocked by required conditions
Checks / Prek / Pre-commit & Formatting (pull_request) Blocked by required conditions
Required
Details
Checks / Prek / Clippy and Cargo Tests (pull_request) Blocked by required conditions
Required
Details
Checks / Changelog / Check changelog is added (pull_request_target) Successful in 8s
Required
Details
Some required checks are missing.
Some workflows are waiting to be reviewed.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u Sync--$ME-and-$LAZY:Reaster-Sync--$ME-and-$LAZY
git switch Reaster-Sync--$ME-and-$LAZY
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
continuwuation/continuwuity!1690
No description provided.