clarifications made: - the `rdfs:label` of `as:context` is roughly "was created in relation to", citing James Snell in a github issue explaining the intended usage of the `context` property. - most usages of the concept of a "context" include behavior where deleting a context deletes anything within that context. this is not a requirement or recommendation, but it is called out as possible behavior. - exactly how to participate in a context or copy an existing context is protocol-dependent and left out-of-scope of this FEP; to be followed up on in future FEP efforts - examples are simplified to leave out protocol details and focus on publishing and consuming context. a new example 4 is added for demonstrating the extension point for "canonical collections". Reviewed-on: #523 Co-authored-by: a <a@trwnh.com> Co-committed-by: a <a@trwnh.com>
24 KiB
slug | authors | status | dateReceived | trackingIssue | discussionsTo |
---|---|---|---|---|---|
7888 | a <a@trwnh.com> | DRAFT | 2023-03-14 | #68 | https://socialhub.activitypub.rocks/t/fep-7888-demystifying-the-context-property/3021 |
FEP-7888: Demystifying the context property
Summary
ActivityStreams Vocabulary defines the context
property, but it is "intentionally vague". Unfortunately, this makes the definition so vague as to be practically useless. This FEP aims to provide more guidance on possible uses of the context
property, as well as formalizing some best practices.
Overview
(This section is non-normative.)
See "Appendix A: Rationale" for fuller analysis of the definition, as well as use cases that can be mapped onto context
.
In short:
- It is possible for objects to exist within implicit contexts. For example, you might group all objects sharing a certain property value. Properties like
context
,audience
andtag
can be used for similar purposes.context
roughly corresponds to the label "was created in relation to". Compare toaudience
, which roughly corresponds to the label "is considered relevant to". Compare also totag
, which roughly corresponds to the label "is associated with a topic of".
- An explicit
context
embodies purpose. Things grouped by the samecontext
"belong together" in a way that can't be said about things grouped by the sametag
. - Objects with a
context
exist within that context, and are meant to be seen and interpreted in context of something else. In most cases, you do not want to view the object on its own; it should be viewed together with other objects, contextually. Deleting a context might reasonably delete or garbage-collect objects within that context. - You might use
context
to represent a "thread", "topic", "conversation", "room", "channel", "forum", "wall", "guild", "space", "project", or so on.
The requirements below can be summarized like so:
- Publishers can use
context
for signaling which objects belong together purposefully, i.e. objects that are meant to be viewed or processed together. Ideally, make thecontext
resolve to something useful. Depending on which properties the resolved context has, various use cases can make use of those properties.- For example, if the context is
attributedTo
some owner, others can keep that owner in the loop when interacting with their context. Similar considerations apply tofollowers
andaudience
. - If the context has some canonical collection associated with it that represents the contents of that context, then that collection can be used for backfill, authorization, moderation, synchronization, and so on.
- For example, if the context is
- Consumers can use
context
to group related objects by the context'sid
. The graph source for those objects is up to you, but in the case where your source is an SQL database, it probably makes sense to have thecontext.id
be the value of a column which is indexed so you can efficiently use a WHERE clause in your query.- Declaring a context does not imply that the context owner acknowledges that object. A canonical collection can help with verifying this for the purpose of authorization or moderation.
- Interactions with an object that has a
context
might exist within that same context, or they might declare their own context, or they might not declare a context. If you're declaring someone else's context, then you might want to keep them in the loop, in the same way that you'd keep someone in the loop if you replied to their object or tagged their object. This would be signaled viacontext.attributedTo
similarly toinReplyTo.attributedTo
ortag[*].attributedTo
.
Publishing context
When generating an object with a context
as a publisher:
Purpose
A context
SHOULD have a purpose; consider tag
for looser references. Objects sharing a certain context
SHOULD be strongly related and intended to be viewed in the same grouping. Deleting the context
MAY delete all objects within that context.
Dereferencing and resolving
A context
SHOULD be resolvable. The resolved object or link can describe the context with at least the additional information needed to fully process the activity or object. Examples of generally useful properties include but are not limited to:
attributedTo
denotes the authority for that context. (This authority might be a good target for addressing and delivery of related activities.)audience
indicates intent for or potential interest by some entities. (These entities might be a good target for addressing and delivery of related activities.)followers
signals that the context might be a followable object. (This followers collection might be a good target for addressing and delivery of related activities.)outbox
might contain relevant Activities performed by the context, if it is an actor.
Ideally, the resolved context
SHOULD in some way have an associated Collection which can contain the related items. (The exact semantics of discovering this Collection are out of scope of this FEP.)
Consuming context
When encountering an object with a context
as a consumer or browser:
Group objects by context
At minimum, you SHOULD consider the current object alongside other objects referencing the same context
(by id
) instead of considering the current object independently. By default, the graph source for objects that are being considered for inclusion is arbitrary. This can be some dataset, or it can be some relevant collection's items. For example, you might conssider the outbox and/or inbox of one or more actors, or you might consider a specific property path on the context
(if resolvable).
Canonical collections of objects within an authoritative context
If the context
resolves to an object of a certain type, then that type MAY indicate that a certain relation represents a canonical Collection of all objects that the authority considers to be included. (The definition of such types and relations is out of scope of this FEP.)
For authoritative contexts that include such a canonical Collection, you SHOULD NOT assume that an object has been accepted into that collection simply because it declares context
. Consumers SHOULD make efforts to verify reverse claims of inclusion. If a client or user-agent is unable to verify this claim, then the client or user-agent SHOULD indicate to users that the object's claim of being included in the authoritative context is unverified. Criteria for establishing proof of inclusion in a collection is out of scope for this FEP, but might include:
- Viewing the collection directly and encountering the object as a collection item
- Querying the collection via some querying mechanism that allows determining if a given object is included in a collection.
- Having knowledge that the authority Added the object to the collection, with knowledge that the object wasn't subsequently Removed.
Interacting with context
Choosing whether to participate in the same context
When encountering an object with a context
and choosing to author your own object or activity that interacts with this object:
- You MAY copy a
context
as-is, if you wish for your object to be included in that same context. - You MAY set your own
context
, if you wish for your object to exist in a different context. - You MAY remove the
context
entirely, if you wish for your object to exist on its own.
Note that context
can be present on either the object, the activity, or both. It is also possible for different context
references to be placed on each. This depends on how context
is used within a given protocol. Protocol considerations for when to use certain contexts are out-of-scope for this FEP. Protocol considerations for how to negotiate participation in someone else's context are also out-of-scope for this FEP.
Keeping relevant entities in the loop
Per PUB Section 6.1 "Client Addressing":
Clients SHOULD look at any objects attached to the new Activity via the
object
,target
,inReplyTo
and/ortag
fields, retrieve their actor or attributedTo properties, and MAY also retrieve their addressing properties, and add these to theto
orcc
fields of the new Activity being created. Clients MAY recurse through attached objects, but if doing so, SHOULD set a limit for this recursion. (Note that this does not suggest that the client should "unpack" collections of actors being addressed as individual recipients).Clients MAY give the user the chance to amend this addressing in the UI.
This FEP extends the recommendation to look at object
, target
, inReplyTo
, and/or tag
to also include context
.
If copying someone else's context, you SHOULD send your activity to the owner(s) of the context(s), defined via context.attributedTo
if resolvable. This is similar to how one might address the author of an object that they are responding to via inReplyTo.attributedTo
, as a social courtesy. You MAY also want to address context.followers
and/or addressing properties like context.audience
.
Appendix A: Rationale
(This section is non-normative.)
The existing definition
From the current definition in VOCAB: https://www.w3.org/TR/activitystreams-vocabulary/#dfn-context
Identifies the context within which the object exists or an activity was performed.
The notion of "context" used is intentionally vague. The intended function is to serve as a means of grouping objects and activities that share a common originating context or purpose. An example could be all activities relating to a common project or event.
Aside from being "intentionally vague", the definition is also somewhat circular; it requires knowing what a context is and having some conceptual understanding of the notion of "context". However, we are given some guidance towards its "intended function", which is to group objects by some common purpose or origin.
Supporting statements from spec authors
In a GitHub issue from ActivityStreams 2.0's development cycle, James Snell provides the following example:
{
"type": "Note",
"content": "This is a note",
"scope": {
"type": "Organization",
"name": "My Employer"
},
"to": ["john@example.com", "sally@example.com"],
"context": {
"type": "http://example.org/types/Project",
"name": "A Project"
}
}
James Snell then comments that:
- The
scope
indicates that the audience for the note is only members of the Organization.- The
to
indicates specific people who should be actively notified.- The
context
indicates a larger context within which the note exists.
James Snell then clarifies (emphasis added):
scope
is not access control [...] a consuming implementation may include the note on the activity timeline of anyone associated with the "My Employer" organization, but it would only notify two individuals listed by theto
property. Thecontext
property, on the other hand, has absolutely nothing to do with audience targeting. The above note is essentially saying, "This is a note that was created in relation toA Project
. Make the note available to anyone in theMy Employer
organization but specifically notify John and Sally"
Therefore, we can establish that context
as a property roughly translates to a label of "was created in relation to".
In a separate issue, James Snell provides another explanation:
The context is really intended to allow objects and activities to be logically grouped. For instance, in an enterprise setting, the context may group activities by project while the scope would identify one or more teams for which the activity is considered relevant, while the to/cc fields are used to indicate specific individuals to notify.
scope
was later renamed to audience
, but the two properties remain closely related and are presented together in AS2-VOCAB Section 5.1.1 "Audience and Context":
Activities are rarely isolated events. Often, multiple individual activities will be performed around a similar context or audience. For instance, a collaborators working on a shared project might perform multiple related activities in the process of achieving some goal. Such activities can be logically grouped together using the context property, and scoped to a particular audience using the audience property.
Purpose and intent; or, why not use a tag?
We might similarly use a tag
for grouping objects and activities. Several fediverse projects often include a Hashtag
(defined as an extension within the ActivityStreams namespace, but not actually adopted or defined formally). This Hashtag
signals an intent to be included or discovered through a collection of objects bearing the same Hashtag
, uniquely identified by its name
. The maintenance of such implicit collections is assumed to be the responsibility of the receiving server, although an href
might be provided for convenience, in order to browse the implicit collection of tagged objects as seen from that origin server. (This also makes the Hashtag
a sub-type of Link
.)
The key property of such a tag is to signal a general, implicit association by reference. We might then consider a context to be an explicit association, but such an explicit association requires an explicit definition.
The different types of context, and how they are actually the same
Various dictionaries define context generally as something that helps you understand the situation. Following from this, the context should be something that helps you process the activity or object. Ignoring the context may lead to misunderstanding the activity or object; the object or activity exists within that context, and should be understood in context of that context.
Specific contexts can be thought of in several applications:
- the "authoritative context" is a context in which some authority can be applied;
- the "conversational context" is a context which represents some conversation and possibly its history;
- the "originating context" is a context which represents some intended starting point that you might look at first.
We might continue to articulate further types of contexts, but the general pattern that emerges is that a context exists to form a purposeful grouping, regardless of the specific purpose. For example, if we had the notion of a conversation, then we might reasonably say that someone owns this conversation and can apply their authority to it. Looking at some object or activity within this context is generally not recommended on its own; it is better to view the entire conversation or some page of it rather than viewing a singular object.
Sample workflows and use-cases involving context
The context may be presented using the following abstractions:
- A "topic" in a forum presentation
- A "conversation" in a social networking presentation
- A "room" in a chatting or messaging presentation
- A "thread" in any of the above contexts (forum thread, social media thread, chat thread)
Contexts may be associated with other contexts:
- A forum topic/thread may be nested in a "forum" or "forum category", and may be nested in another parent forum as a sub-forum.
- A "wall" on a social networking profile may contain conversations, which in turn contain the posts/comments
- A "guild" or "space" may contain multiple chat rooms with a common audience
It is also possible to not have a context. Such objects exist only in the general context of their author (via attributedTo
) or other implicit contexts, and are otherwise self-sufficient.
Considerations on when to use context include:
- If deleting a context, then objects within that context might reasonably be deleted or garbage-collected since they have lost their purpose.
Appendix B: Examples
(This section is non-normative.)
Example 1: A minimal example for grouping objects by context
This example demonstrates how objects sharing the same context can be logically grouped together.
You encounter the following object:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-object",
"context": "https://domain.example/some-context",
"summary": "<some-object> exists in <some-context>."
}
You wish to participate in the same context, so you dereference the context in order to learn more about it:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-context",
"attributedTo": "https://domain.example/context-owner",
"summary": "<some-context> is owned by <context-owner>."
}
You create an object, while copying that context onto your object:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/your-object",
"context": "https://domain.example/some-context",
"summary": "<your-object> exists in <some-context> as well."
}
Distribution occurs somehow; you may want to notify the <context-owner>
or seek their acknowledgement of your object, but these things are out-of-scope of this example. A graph source or dataset containing these two objects may be queried for objects sharing the same context:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/results-for-your-query",
"type": "Collection",
"summary": "The <results-for-your-query> show that 2 items have a context of <some-context>. They are <some-object> and <your-object>.",
"totalItems": 2,
"items": [
"https://domain.example/some-object",
"https://domain.example/your-object"
]
}
Example 2: Choosing not to participate in the same context
This example demonstrates how objects can have different contexts, indicating that they were created for different purposes. Though they may be grouped by other criteria, they do not share a primary reason for existing.
You encounter the following object:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-object",
"context": "https://domain.example/some-context",
"summary": "<some-object> exists in <some-context>."
}
You want to establish your own context, separately from the current object's context:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/a-different-context",
"attributedTo": "https://domain.example/you",
"summary": "<a-different-context> is owned by <you>."
}
You may declare that your object is in some way a response to the object that you encountered, but because the contexts are the same, they do not share a primary grouping:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/your-object",
"inReplyTo": {
"id": "https://domain.example/some-object",
"context": "https://domain.example/some-context",
"summary": "<some-object> exists in <some-context>."
},
"context": "https://domain.example/a-different-context",
"summary": "<your-object> is a response to <some-object>, but <some-object> exists in <some-context> while <your-object> exists in <a-different-context>."
}
Querying replies for the original object might surface your object, but querying the context for the original object will not surface your object.
Later, <some-context>
is deleted. In some cases, <some-object>
might be garbage-collected, since it has lost its reason or purpose for existing; at best, it is considered orphaned. However, <your-object>
continues to exist because it was created in <a-different-context>
which still exists.
Example 3: Encountering multiple contexts
This example demonstrates how one might deal with objects that have multiple contexts.
You encounter an object with multiple contexts:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-object",
"context": ["https://domain.example/some-context", "https://domain.example/some-other-context"],
"summary": "<some-object> exists in <some-context> and <some-other-context>."
}
You dereference the two contexts:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-context",
"attributedTo": "https://domain.example/context-owner",
"summary": "<some-context> is owned by <context-owner>."
}
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-other-context",
"attributedTo": "https://domain.example/other-context-owner",
"type": "Object",
"summary": "<some-other-context> is owned by <other-context-owner>."
}
As a third-party observer, you can choose to browse either context.
As a third-party interactor, you can choose to declare an object in either context, both contexts, a different context, or no context.
The protocol considerations for which contexts are considered valid or acceptable are out-of-scope of this FEP, but dereferencing the contexts can provide more information that can help you make this choice. Perhaps you expect a certain type to be declared, or perhaps you require an owner, or perhaps some other criteria is enforced.
Example 4: Publishing, consuming, and interacting with authoritative contexts that have canonical collections
This example demonstrates how one might expose all objects acknowledged by a context owner to exist within the context.
You encounter the following object:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-object",
"context": "https://domain.example/some-context",
"summary": "<some-object> exists in <some-context>."
}
You wish to browse that context, so you dereference the context:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://domain.example/some-context",
"attributedTo": "https://domain.example/context-owner",
"type": "https://w3id.org/fep/xxxx/Conversation",
"https://w3id.org/fep/xxxx/posts": {
"id": "https://domain.example/some-context/posts",
"type": "OrderedCollection",
"items": [
"https://domain.example/some-object",
// ...
]
}
"summary": "<some-context> is owned by <context-owner>. It is a <Conversation> and it has a canonical collection of <posts>, which is <some-context/posts>."
}
As a consumer, you can browse or backfill the conversation by loading the context's canonical collection. In the above representation of <some-context>
, the use of the hypothetical https://w3id.org/fep/xxxx/Conversation
type would indicate that the associated canonical collection is exposed via the hypothetical https://w3id.org/fep/xxxx/posts
property.
Appendix C: Creating and maintaining contexts and their associated collections using ActivityPub C2S
(This section is non-normative.)
Because PUB does not define the use of context
as a property or the notion of a canonical collection, it is up to ActivityPub Clients to manage contexts and their canonical collections for themselves. The following algorithm may be used to create an object within a context that has a canonical collection:
Create
the canonicalCollection
that will be associated with the context. Save the generated Collectionid
to be used in the next step.- Create the Object that will be used as
context
. If the Object has a canonical Collection associated with it, then specify the appropriate property relation using theid
from the previous step. Save the generated contextid
to be used in the next step. - Create the Object that will exist within the context, and specify the
context
as theid
from the previous step. Set an appropriateaudience
or useto
/cc
to deliver the Create activity as-is. Save the generated objectid
to be used in the next step. - Add the Object to the context's canonical Collection, using the
id
s obtained from the responses for steps 1 and 3. You may wish to deliver this Add activity viato
/cc
/audience
targeting your intended recipients, especially if you did not deliver the Create Object from step 3.
References
- VOCAB James M Snell, Evan Prodromou, Activity Vocabulary, 2017
- PUB Christine Lemmer Webber, Jessica Tallon, ActivityPub, 2018
Copyright
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.