This document specifies a model for managing conversations in ActivityPub network. It is based on the implementation of Conversation Containers in Streams.
In this model conversations are represented as collections controlled by a single actor. Such conversations take place within a specific audience and may be moderated.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC-2119.
A conversation container is implemented as a collection. Every item in that collection is an Add activity where object is another activity (such as Create, Update, Delete, Like, Dislike, EmojiReact or Announce). The conversation owner distributes Add activities to other participants, thus keeping their views of the conversation synchronized.
OrderedCollection.attributedTo property containing the id of the conversation owner.collectionOf property with value Activity.[!NOTE] The required collection type might be changed to a more descriptive one (such as
ConversationContainer) in a future version of this document. That will allow identification ofAddactivities belonging to a conversation container by the value ofAdd.target.type.
[!NOTE] In addition to the conversation container collection, implementers MAY provide collection that represents the conversation tree and contains posts.
Conversation owner can add any activity to the conversation. However, if a context property is present on the activity, its value SHOULD be identical to the ID of a conversation container.
When activity is added to the conversation, its owner sends an Add activity to the conversation audience (usually defined by a top-level post).
Add activities published by the conversation owner MUST have a target property containing a partial object:
type: OrderedCollectionid: the id of the conversation container.attributedTo: the id of the collection owner.Add activities published by the conversation owner MUST be added to the conversation container collection.
[!NOTE] The “conversation outbox” model where the
targetofAddactivity is a collection ofAddactivities is not compatible with ActivityStreams definition of Add activity, according to which Add activity indicates that the actor has added the object to the target.
The author of a top-level post it not necessarily the conversation owner. When owner is a group, conversations can be started by any of its members.
The top-level post MUST have a contextHistory property that refers to the conversation container. The presence of this property indicates that publisher implements conversation containers.
[!NOTE] In addtion to
contextHistoryproperty, implementers MAY add acontextproperty that refers to a collection of posts.
All activities in a conversation SHOULD only be delivered to the conversation owner.
Conversation participants SHOULD reject conversation activities that have not been added to the conversation by its owner.
The audience of a reply MUST be copied from a conversation root.
Reply with a different audience can be created by starting a new conversation and including a FEP-e232 link to the post instead of specifying it in inReplyTo.
When conversation owner does not want to add activity to a conversation, that activity is ignored and a corresponding Add activity is not published.
To remove a previously approved post from a conversation, its owner publishes a Delete activity where object is the post that must be removed. This activity is then wrapped in Add activity and distributed to the conversation audience.
[!NOTE] Actor shouldn’t be able to delete objects it didn’t create. In a future version of this document
Deletemight be replaced withRemove(target: Thread).
Conversation participants can retrieve missing activities by reading the conversation container collection.
When an ActivityPub server receives an Add activity in its inbox, it MUST perform the authentication procedure according to FEP-fe34:
Add.object is not embedded, fetch it. If location of the fetched activity has the same origin as Add.object, add it to the conversation.Add.object is embedded, check whether Add.actor and Add.object.actor have the same origin.Add.object to the conversation.Add.object to the conversation.Add.object by its id. If location of the fetched activity has the same origin as Add.object.id, add fetched activity to the conversation.The processing of unauthenticated embedded activities is strongly discouraged. If such activities are not rejected by the consumer, a malicious conversation owner may be able to perform a cache poisoning attack and overwrite any actor or a post in consumer’s local cache by sending a forged Update(Actor) or Update(Object) wrapped in an Add activity.
[!WARNING] Sometimes activities have non-dereferenceable identifiers. That may prevent their authentication.
Example of an Add activity for a reply to a followers-only post:
{
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"type": "Add",
"id": "https://alice.example/activities/add/1",
"actor": "https://alice.example/actors/1",
"object": {
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"type": "Create",
"id": "https://bob.example/activities/create/1",
"actor": "https://bob.example/actors/1",
"context": "https://alice.example/contexts/1",
"object": {
"@context": [
"https://www.w3.org/ns/activitystreams"
],
"type": "Note",
"id": "https://bob.example/posts/1",
"inReplyTo": "https://alice.example/posts/1",
"content": "This is a reply",
"to": [
"https://alice.example/actors/1",
"https://alice.example/actors/1/followers"
]
},
"to": [
"https://alice.example/actors/1",
"https://alice.example/actors/1/followers"
]
},
"target": {
"type": "OrderedCollection",
"id": "https://alice.example/contexts/1",
"attributedTo": "https://alice.example/actors/1"
},
"to": [
"https://bob.example/actors/1",
"https://alice.example/actors/1/followers"
]
}
Example of a container of a followers-only conversation:
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/fep/171b"
],
"type": "OrderedCollection",
"id": "https://alice.example/contexts/1",
"attributedTo": "https://alice.example/actors/1",
"collectionOf": "Activity",
"orderedItems": [
"https://alice.example/activities/add/1"
]
}
Announce activity is used instead of Add. Conversation and related activities are synchronized between participants, but conversation backfilling mechanism is not specified.Accept or Reject activity is generated for every interaction (in a conversation container Add activity is generated when activity is approved, and rejected activities are ignored). Conversation is not synchronized between participants, but can be backfilled by recursively fetching replies collections.CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
To the extent possible under law, the authors of this Fediverse Enhancement Proposal have waived all copyright and related or neighboring rights to this work.