+++ title = "Disambiguating various interpretations of a \"quote\" feature" summary = "Broadly speaking, there are [...] Quote replies (reply with adjacent contextual preview) [...] Quote tags (rich quotes embedded in content) [...] [and] Quote boosts (reshare with comment)" date = 2023-07-18T21:17:00-05:00 updated = 2024-11-13T11:27:12-06:00 toc = true autonumbering = false streams = ["all"] tags = ["quote post", "quote tweet", "quote reply", "quote boost", "reshare with comment", "activitypub", "as2", "fedi"] [[params.inReplyTo]] [[params.syndication]] name = "Original post on SocialHub" url = "https://socialhub.activitypub.rocks/t/disambiguating-various-interpretations-of-a-quote-feature-pre-fep/3426" +++ 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".[^what-are-mentions] Following this logic, Mastodon's implementation of ActivityPub defined extensions for `https://www.w3.org/ns/activitystreams#Hashtag`[^as-hashtag] 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)[^sanitizing-content] `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: `, 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. [^what-are-mentions]: (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 type `Mention` in order to determine delivery and addressing. Addressing someone in `to`/`cc` without mentioning them will create a "silent mention".) [^as-hashtag]: (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.) [^sanitizing-content]: 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 into `name` (or `href`) compared to what they put into `content`. ### 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.[^announce-as-forwarding] 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. [^announce-as-forwarding]: 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. ### The quote activity Instead of an `Announce` with `content`, we can define a new Activity type `Quote` that can be used similarly, but has different semantics. Whereas an `Announce` is defined like so: > Indicates that the `actor` is calling the `target` 's attention the `object`. So instead of "calling for attention", the `Quote` activity would instead be defined semantically as: Quote : Indicates that the `actor` is quoting the `object` verbatim in its entirety. The "quote activity" might also instead be named something else to avoid potential conflicts with other shorthand terms. Something like `Cite` could also work. Alternatively, other disambiguated senses of the word may be represented in the noun form as a `Quotation` or `Citation`. ## 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. ### Quote activities (new extension Activity type) - (~) No fallback. This could be either good or bad, depending on if you want a fallback or if you want the semantics to be respected. - (+) With the existence of a `quotes` collection (even if the `items` might be private), we can use its IRI as the `target` of an `Add` which acts as a stamp of inclusion in a parallel way to how one might signal an Add into the `likes`, `shares`, `replies`, `context`, etc collections. - (+) In theory supports one or multiple `object` references, but even if you limit the cardinality to 1, this at least "frees up" the `inReplyTo` property for cases where you might reply to one post while quoting a different post. It also remains possible to `Quote` an `object` while also declaring that your `Quote` is `inReplyTo` the same `object`.