fix(channel): carry attachments, and their captions #107
No reviewers
Labels
No labels
blocked
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
waiting-on-julian
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jlxq0/matrix-mcp!107
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "channel-attachments"
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?
Closes #106.
Three of Julian's messages never reached the agent tonight, each carrying a real
instruction. They were found only by dumping the room and grepping for
msgtype != m.text.The reasoning was sound and the premise was wrong
channel.rsfiltered onMessageType::Text, deliberately, and said why:True of an uncaptioned upload. False of a captioned one — and Element on a
phone puts a photo's caption in
content.body, which is the traffic thatactually arrives here.
The rule was already in this repository.
mcp.rs:5245, on the send side:Two paths, 4,600 lines apart, holding opposite premises about one field — and
the one that implements the spec was not the one the channel used.
split_captionis that rule applied on the way in.
What changes
m.image,m.file,m.audioandm.videoare carried as attachmentsrather than dropped:
An agent can now tell "somebody said this" from "somebody sent a file called
this".
roomandeventwere already in the meta, sodownload_attachmentneeds nothing new to fetch the bytes.
An uncaptioned upload delivers no prose at all. Its filename is metadata and
travels as an escaped attribute. The original objection was that a filename must
not masquerade as a message — labelling it is the fix, not dropping the event.
Replay changes with it, and that is the half that made this invisible
read_events_from_chunkfillsuntrusted_bodyfromcontent.bodyfor anyevent that has one. So a caption dropped live reappeared on the next attach —
hours later, out of order, with nothing marking it as late.
That is why this presented as "Julian's messages are sometimes slow" rather
than "images are dropped". A message that never arrives is noticed; one that
arrives late and unlabelled is explained away.
carried_ofis the same classification for the replay path, so the two nowagree in both directions — including refusing to replay an uncaptioned
upload's filename as prose, which is the mistake the live path was avoiding.
Security
A caption is untrusted prose from the same sender as any other message, so it
goes through
content_sandbox::evaluateon both paths, unchanged. Filenames aresender-chosen too and are escaped as meta values rather than trusted for looking
like filenames — the existing
meta_values_cannot_break_out_of_the_attributetest covers that escaping.
Nothing new is exposed: no
mxc://, no new tool, no new surface.Verification
Clippy is clean apart from two
unknown linterrors that are present onmaintoo — this machine's clippy is older than the pins inmcp.rs.Confirmed by running clippy on a stashed tree.
The four new tests were checked against broken code. Deleting the caption
arm of
split_caption— which restores the old premise exactly — failsa_captioned_upload_yields_the_caption_and_the_filenameanda_captioned_image_is_carried_as_an_attachment, and leaves the other twelvegreen. So they can tell.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SP7njJZ7ZtrMgULuXh8ddq