The receiving half already worked. `Content.Reference` was in use for
reactions, an inbound reply was recognised and rendered, and `Session.Line`
already had an `about` field to hold one. What was missing was any way to START
one: no Reply in the long-press menu, no composer state, and `Session.send` had
nowhere to put a reference.
So this is narrow, as the ticket said: `Session.send(replyTo:)` passes the
reference to `Content.text(about =)` and records it locally, a Reply item sits
above Forward in the menu, and a dismissible strip above the composer says who
is being answered.
🔴 **The preview travels with the reply, and dropping it to save bytes is not a
free optimisation.** A recipient who joined the thread later or cleared their
history has never seen the message being answered — "> [missing]" is worse than
showing what was said. A test says so rather than a comment.
⚠️ **Visible before it is sent.** A reply that only appears in the sent message
is a mode nobody can see they are in, and the commonest way to answer the wrong
message is not to know you were answering one.
⚠️ **1:1 only, and the menu item is ABSENT rather than disabled in a group.**
The group send path does not carry a reply yet; accepting one there and dropping
it would be a half-feature that looks whole. The same reasoning the file already
applies to Edit and Pin on messages written before ids existed.
Three wire tests. One of them pins that a message which is NOT a reply still
goes out as a bare body — adding this must not have turned every plain message
into an envelope an older peer reads differently.
⚠️ Not included, and its own piece: tapping the quote to jump to the message it
names. That needs a scroll-to-id in the transcript list.
158 tests, 0 failures.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>