Carry Matrix threads in both directions, and read channel state back - #17
Merged
Merged
Conversation
Inbound: chat_poll and chat_history map an event's m.relates_to onto chat_message$thread when its rel_type is m.thread. Only that rel_type counts -- a rich reply carries an m.in_reply_to with no rel_type, and reading that as a thread would report every quoted reply as one, which chat_message has no reply_to slot to undo. A threaded event carries an m.in_reply_to too, as its fallback, so the test is rel_type and not the relation's presence. Outbound: chat_send passes thread through to mx_send_text, and the rich path builds the same relation itself since it bypasses that function. The argument is named only when there is a thread, so an mx.client predating it keeps working for ordinary replies. thread_replies is now TRUE. threads is TRUE when the installed mx.client can attach a relation (0.2.0.5) and the client is not e2ee: the encrypted send path has nowhere to put an m.relates_to, so a threaded send there is refused rather than posted to the room's main timeline -- files' bargain, not rich's, because a reply that leaves its thread is misrouted rather than merely undecorated.
chat_get_state() is the counterpart of chat_set_state(), on the same set_state capability: a transport with durable channel state has both halves or neither. Matrix reads through mx.api::mx_get_state with an injectable .get_state seam; loopback reads its keyed store. State that was never written reads as NULL rather than erroring -- "no marker here" is an ordinary answer for a caller checking whether one is set, and it should not need a handler to get it. A state store that cannot be reached at all still errors, because that is a different fact. Needed by threaded rehydration, which maps a thread root to the archive it stands for by reading an index the fold wrote into the topic room's state; with only a setter that lookup would have to drop below the transport seam.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two additions chat.api needs before a threaded reply can be routed and rehydrated.
Threads, both directions. Inbound, chat_poll and chat_history map an event's m.relates_to onto chat_message$thread when its rel_type is m.thread. Only that rel_type counts — a rich reply carries an m.in_reply_to with no rel_type, and reading that as a thread would report every quoted reply in a room as one, which chat_message has no reply_to slot to undo afterwards. A threaded event carries an m.in_reply_to too (its reply fallback), so the test is rel_type rather than the relation's presence.
Outbound, chat_send passes thread through to mx_send_text, and the rich path builds the same relation itself since it deliberately bypasses that function. The argument is named only when a thread is given, so an mx.client predating it keeps working for ordinary replies instead of failing with an unused-argument error.
thread_replies is now TRUE: reading a relation needs nothing but the extractor field every supported mx.client carries. threads (the send side) is TRUE only when the installed mx.client can attach a relation (0.2.0.5, probed rather than assumed) AND the client is not e2ee — the encrypted send path has nowhere to put an m.relates_to, so a threaded send there is refused rather than posted to the room's main timeline. That is files' bargain rather than rich's: a reply that leaves its thread is misrouted, landing where nobody is looking and where a consumer keying state off the thread will never see it, not merely undecorated.
chat_get_state(). The counterpart of chat_set_state(), on the same set_state capability — a transport with durable channel state has both halves or neither. State never written reads as NULL rather than erroring, because "no marker here" is an ordinary answer for a caller checking whether one is set; a store that cannot be reached at all still errors, since that is a different fact. Threaded rehydration maps a thread root to the archive it stands for by reading an index the fold writes into the topic room's state, and with only a setter that lookup would have to drop below the transport seam.
The mx.client Suggests floor deliberately stays at 0.2.0.4: threaded sending degrades honestly through the capability probe, so forcing an upgrade on consumers that never thread would be wrong.
Second of three PRs wiring threaded replies up the stack. Depends on cornball-ai/mx.client#23 for the send half only; merges and passes independently of it (the probe reports FALSE until that lands). Four existing assertions that pinned the old "threads are unreachable" contract are updated to the new one, and the real-extractor integration test now round-trips a threaded event through the installed mx.client.