Skip to content

Latest commit

Β 

History

History
77 lines (63 loc) Β· 4.05 KB

reactions.md

File metadata and controls

77 lines (63 loc) Β· 4.05 KB

Message reactions

Status: deployed, integration-tested, and accepted in the reference web client

Telex implements durable message reactions as progressive IRCv3 client-tag state. A reaction is owned by an authenticated account and attached to one retained message. It is not a chat message, does not move a read or delivery cursor, and does not extend the parent's retention lifetime.

IRC wire shape

A client must negotiate message-tags and send TAGMSG with the retained parent's canonical msgid:

@+reply=<parent-msgid>;+draft/react=πŸ‘ TAGMSG #room
@+reply=<parent-msgid>;+draft/unreact=πŸ‘ TAGMSG #room

The target may be a joined channel or an accessible direct-message target. The parent ID must belong to that exact conversation and still retain its message body. Reaction values contain 1–64 UTF-8 bytes and no control characters. One account may hold at most 16 distinct values on a message, and one message may hold at most 240 account/value rows.

Adding existing state or removing absent state is an idempotent no-op. A real change is relayed as TAGMSG with a server-assigned msgid and, when negotiated, time and account. Channel membership and direct-message policy are checked through the ordinary messaging boundaries. With standard-replies, invalid requests receive FAIL TAGMSG; otherwise Telex uses a generic protocol error.

History and retention

CHATHISTORY continues to count and page only retained PRIVMSG and NOTICE events. Immediately after each returned parent, Telex emits its current reaction rows as +draft/react TAGMSG entries inside the same history batch. Those snapshot rows do not consume the requested message limit and do not advance account read markers or installation delivery checkpoints. If reactions make a multi-message response exceed the bounded connection output budget, Telex returns CHATHISTORY LIMIT_EXCEEDED so the client can retry with a smaller message limit; every valid one-message snapshot fits.

The separate reaction table stores only current state. Removing a reaction does not leave a tombstone in chat history. Pruning a parent first deletes its reactions, and a content reset removes them through the parent conversation. Consequently a reaction cannot preserve attribution or content beyond the retained message it annotates.

Compatibility

Telex sends reaction frames only to clients that negotiated message-tags. It does not manufacture fallback PRIVMSG, NOTICE, status-buffer text, or numerics for recipients. Clients that understand tags but not reactions can silently ignore the unknown client-only tags and TAGMSG; clients without message tags receive the ordinary message only. Bounded legacy JOIN replay likewise remains message-only.

HexDroid uses an older, internally consistent dialect: it negotiates draft/message-reactions, sends the parent as +draft/reply, and removes a reaction with +draft/react-removed. Telex advertises that name as an explicit compatibility marker, requires it to be negotiated together with message-tags, and accepts those aliases only on a connection that negotiated the marker. If canonical and compatibility tags are both present, their values must match. Telex still stores one canonical reaction state and emits canonical +reply plus +draft/react or +draft/unreact; recipients that negotiated the compatibility marker also receive +draft/react-removed on removal. Other clients never receive that extra alias. This compatibility path is deployed and has passed live HexDroid add/remove acceptance.

The reference web client renders compact counts, shows the reacting accounts, and currently offers thirteen quick choices: πŸ‘, ❀️, πŸ˜‚, πŸŽ‰, πŸ‘€, πŸ€”, πŸ³οΈβ€πŸŒˆ, 😭, 🀝, πŸ‘Ž, πŸ‘πŸΏ, πŸ‘ŽπŸΏ, and 😩. This is only a shortcut palette, not a reaction allowlist; the wire and storage model continue to accept any valid bounded reaction value. Reaction changes are stored beside their parent in the browser's bounded IndexedDB transcript and are refreshed from the server's current history snapshot after reconnect.