The operator swiped a voice note to quote it and got the raw
aesgcm://…#<key> URL in the quote. db.ts has labelled attachments for the
chat-list preview since package 9, with the comment that the preview never
shows that URL because it carries the file key — the quote path never did
the same.
quotedText now names the attachment, and displayQuote names an aesgcm://
line at render time too, for history written before this and for whatever
a remote client sends. Only aesgcm:// lines are replaced: a plain https
link in a quote may simply be a link somebody quoted.
This was never a leak over the wire. In an encrypted chat the quote rides
in the same envelope as the original, and send() refuses an encrypted
quote into a chat that is not capable. What it was: the file key copied
into a second message's body for nothing, and a wall of hex where a human
expects "Voice message".
Checks: 95 tests, two of them new and specific to this; zero svelte-check
errors; build; SWIPE-QUOTES-ATTACHMENT-BY-NAME uploads a real encrypted
image, swipes it and asserts the preview, the sent quote and the outgoing
stanza; ux-swipe-runner.cjs 12/12 and ux-reactions-runner.cjs 14/14 under
both engines, zero page errors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>