Report upstream: continuwuity sliding sync stamps initial without honoring the required_state wildcard #71
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Field finding from the #66 thread (D34 addendum 3): continuwuity 26.7.2 (prod, centoria.de) answers MSC4186 sliding sync with initial:true room payloads whose required_state omits state the [["",""]] wildcard should deliver (observed: m.room.encryption absent for an encrypted DM; Synapse 1.157.2 container e2e delivers it — SlidingStateDeliveryEndToEndTest). katrix now defends itself (transmit probe + explicit required_state entry), but the server behavior deviates from MSC4186 and hurts every client trusting initial payloads. Task: minimize a repro against a continuwuity container and file it upstream at forgejo.ellis.link/continuwuation/continuwuity; consider adding a continuwuity leg to the e2e matrix afterwards.
Repro minimized against a pristine
forgejo.ellis.link/continuwuation/continuwuity:latestcontainer — which reports 26.7.2 (59c2649), same as prod. Probe matrix (each probe is a fresh sliding connection, so always the initial payload; room is an encrypted private chat the syncing user just joined):[["*","*"]][["m.room.encryption",""]][["*","*"],["m.room.encryption",""]][["m.room.member","*"]]So it is sharper than the prod observation: the type-level wildcard delivers nothing at all — not merely missing m.room.encryption. The state_key wildcard on a concrete type works; explicit entries work (which confirms the D34-addendum-3 belt: our explicit entry beside the wildcard is exactly what saves us on this server).
Cause, confirmed in source (
src/api/client/sync/v5.rs,collect_required_state, current main): the loop handlesstate_key == "*"by enumerating keys for a concrete type, but an event type of"*"is treated as the literal type string —room_state_get(room_id, "*", …)matches nothing, and the payload still goes out stampedinitial: true.Context worth knowing before filing: upstream issue 1661 ($ME/$LAZY not resolved) was closed as "not a Continuwuity issue" because those sentinels were removed in the current MSC4186 revision. The
*wildcard argument is different — continuwuity accepts the tuple request format and expands the state_key wildcard, so dropping only the type wildcard is inconsistent with its own format handling, and Synapse 1.157.2 delivers full state for the identical request (SlidingStateDeliveryEndToEndTest).Filing is blocked on a human: no auth for forgejo.ellis.link from this machine, and the maintainers there explicitly asked that AI not be used for communication on their tracker (1661 thread). Draft below — please review, put it in your own words where you see fit, and file it under your account.
Draft title: sliding sync:
["*","*"]type wildcard inrequired_statedelivers no state —initial: truepayloads arrive with emptyrequired_stateDraft body:
Reproduced on a pristine container from
forgejo.ellis.link/continuwuation/continuwuity:latest(reports 26.7.2, 59c2649).Steps: create an encrypted private room (initial_state m.room.encryption), second user joins, then that user's first request to
/_matrix/client/unstable/org.matrix.simplified_msc3575/syncwith"required_state": [["*","*"]]. The room arrives withinitial: trueand an emptyrequired_state. Requesting[["m.room.encryption",""]]explicitly delivers the event, and[["m.room.member","*"]]delivers all member events — so the tuple format and the state_key wildcard are honored; only the type-level*is not.Cause appears to be
collect_required_stateinsrc/api/client/sync/v5.rs:state_key == "*"enumerates keys for a concrete type, but a type of"*"is looked up as the literal event type and matches nothing.Impact: a client that subscribes with the wildcard and trusts an
initial: truepayload to carry the room's state silently sees no state at all. In our SDK's case the missingm.room.encryptionmade an encrypted room indistinguishable from an unencrypted one (a plaintext-into-encrypted-room hazard) until we added a per-room server confirmation. Synapse 1.157.2 answers the identical request with the full state set.Repro script (docker + curl + python3): [attach continuwuity-repro.sh]
Repro script follows in the next comment.
The self-contained repro script (docker + curl + python3; throwaway container, registration-token dance included):
Format clarification (asked in review): the current MSC4186 revision no longer uses the tuple format at all —
required_stateis a typed object (RequiredStateRequest:include/excludelists of{type?, state_key?}elements pluslazy_members), and wildcarding is expressed by omitting a field ({}matches everything). The[["*","*"]]tuple array with"*"sentinels is the earlier MSC4186/MSC3575 wire shape — the one Synapse serves on theorg.matrix.simplified_msc3575unstable endpoint, and the one rust-sdk and katrix send.Why this strengthens the report rather than weakening it: continuwuity is also on the OLD shape. Its ruma request model deserializes
required_stateas(type, state_key)tuples — the current revision's object format would not even parse — andcollect_required_stateimplements the old format's"*"sentinel for state_key while treating a"*"type as a literal event type. So the 1661-style response ("not in the current revision") does not transfer: measured against the current revision the endpoint's whole request shape is the old one; measured against the revision they actually implement, the type wildcard is half-implemented. Either way, answeringinitial: truewith silently empty state is the defect. Worth folding this paragraph into the issue when filing.