Broadly speaking, there are a lot of different, maybe mutually exclusive or incompatible ideas of what a “quote” is, or what it should do, or what it should look like, and so on. Many people, when asking for such a “quote” feature, are drawing inspiration from past features, perhaps more commonly the Twitter “quote tweet” or perhaps alternatively the forum-style “quote” as can be seen on this very Discourse forum. This pre-FEP aims to describe all possible approaches, as well as describing the pros and cons of each approach from both semantic and practical perspectives.
Implementation approaches
The quote reply
The semantic purpose of the inReplyTo
is to denote that the current resource is “in reply to” or considered a response to the linked resource. Very often, a “quote” is semantically a response to the “quoted” resource. What actually makes it a “quote” is purely presentational or display-based; the “quoted” resource is embedded next to the “quote”. This embed can be placed below or above the current resource; because reading often happens top-to-bottom, a placement below the current resource allows the “quote” to act as framing for the “quoted”, while a placement above the current resource allows the “quoted” to provide a contextual preview for the “quote”.
Some implementations differentiate between “replies” and “normal posts”, while other implementations treat all posts the same regardless of whether they are in reply to anything or not. For example, at the time of writing this, Mastodon filters out “replies” from your timeline unless you follow the author of the post being replied to. Pleroma does no such filtering. Akkoma and Misskey make it a user choice. These are once again presentational choices, stemming from implementation-specific UX choices. For an AS2 producer which makes such distinctions, it may be helpful to signal a further distinction between “replies” and “quote replies”; a “quote reply” could be shown in timelines always, or considered the same as a “normal post”. If, for example, Mastodon wanted to adopt this strategy, it could define an extension property like http://joinmastodon.org/ns#quoteReply
which, if set to true
, would treat the resource linked in inReplyTo
as a “Mastodon quote post”, opting into the rendering and timeline-filtering behavior associated with such a concept. An AS2 consumer sharing Mastodon’s UX choices and aware of this property would interpret objects with toot:quoteReply = true
as “Mastodon-style quote posts”. An AS2 consumer not sharing Mastodon’s UX choices can render the reply metadata as it wishes; it is possible to render all replies as “quote replies” by simply embedding a preview of the replied-to resource above the current resource.
The quote tag
The purpose of tag
is to markup the natural-language properties of name
, summary
, and content
. In particular, substrings of content
are often associated with richer metadata. Most commonly, tags of type Mention
are used to associate a specific substring following a microsyntax, @mention
, with a specialized Link that is intended to denote a “mention”.[1] Following this logic, Mastodon’s implementation of ActivityPub defined extensions for https://www.w3.org/ns/activitystreams#Hashtag
[2] and http://joinmastodon.org/ns#Emoji
. The Hashtag
type is used to associate the #hashtag
microsyntax with a “hashtag”, which is a reference to some string. The Emoji
type is used to associate an :emoji:
microsyntax with a “custom emoji”, which is an inline image with a square aspect ratio and the same height as a single line of text. In each of these cases, the name
of the tag denotes the microsyntax, and this substring of the (sometimes plain-textified and HTML-stripped)[3] content
can be replaced with a richer entity. FEP-e232 follows this logic as well; “object links” are tagged as a Link
(or subtype) with appropriate mediaType
, and the name
is used to denote any applicable microsyntax such as RE: <url>
, especially coupled with the use of rel
to specify the link relation.
It is possible to build on FEP-e232 by using “object links” with a link relation specifically denoting a “quote” relationship. Some software such as Foundkey uses the rel-value https://misskey-hub.net/ns#_misskey_quote
to denote a “Misskey quote”, while also accepting http://fedibird.com/ns#quoteUri
and https://www.w3.org/ns/activitystreams#quoteUrl
as equivalent. All three of these IRIs have historically been used as properties to express the same or nearly-identical concept – a single “post” that will be embedded as a preview below yours, separately from what you are replying to, intended to send a notification to the author of the quoted post that they’ve been quoted. It is possible to define standardized semantics using an IRI as a property or as a type, e.g. a Quote
type.
The quote boost
The purpose of a share (Announce
) is to draw attention to, boost, or republish the referenced object. Functionally, when sent to the author of that object, the author can add the Announce activity to the shares
collection on that object. This gets interpreted as a “boost” or “reblog” within most current implementations.[4]
It is possible to add content
to your Announce
activity; a generic presentation of activities can use the natural-language properties name
, summary
, and content
along with actor
type
object
in order to generate a representation of the activity.
Comparison and analysis
Quote replies (reply with adjacent contextual preview)
- (+) The quote reply maintains the best semantics in cases where the author is responding to the quoted object. It also falls back to a regular reply where not understood.
- (+) The quote reply can easily inherit from “reply controls”, which allow authors of objects to grant stamps of approval that offer proof for a given object’s presence in the
replies
collection. - (-) The quote reply is practically (but not theoretically) limited to one “quoted” resource per post. It is possible to reply to multiple objects, although it is not immediately clear how this should be rendered or presented; adding a “quote reply” boolean property would limit the “quote” presentation to an all-or-nothing case, and selecting only some linked resources to be rendered as “quotes” would best be served by one of the other approaches.
Quote tags (rich quotes embedded in content)
- (+) Multiple quote tags would be supported.
- (~) Semantics can be signaled with
rel
or with extension types, but it is important to avoid proliferation of similar or identical semantic IRIs.
Quote boosts (reshare with comment)
- (~) Might be semantically appropriate, if the “sharing” aspect of the “quote post” is what you intended.
- (-) Falls back to a normal boost, without displaying the added content at all.
Footnotes
(The exact meaning of a “mention” is not entirely clear. AS2-Vocab ties the definition to the
@mention
microsyntax, but provides no additional guidance on its intended functionality or meaning. At minimum, there is the implication that the Mention might denote an actor or a user, and might generate some notification that the mentioned entity has been mentioned. Software such as Mastodon follows this interpretation and uses mentions to generate notifications, but also goes further and requires tags of typeMention
in order to determine delivery and addressing. Addressing someone into
/cc
without mentioning them will create a “silent mention”.) ↩︎(Mastodon defining
as:Hashtag
within the activitystreams namespace is technically lacking authority, as only the W3C SocialCG can adopt new terms into the activitystreams namespace or make modifications to the normative activitystreams context. In particular,as:Hashtag
is an inline extension, and it is not defined in the normative context.) ↩︎It is unclear when, how, or if such sanitiziation or stripping of
content
will take place. Current implementations are not entirely consistent with what they put intoname
(orhref
) compared to what they put intocontent
. ↩︎Some software implementations do not use
Announce
as a reshare activity, and instead use it for other purposes outside of a publishing context, such as wrapping and forwarding someone else’s activity. The intended specified mechanism for doing this is inbox forwarding. ↩︎