How do you use `context` (if at all)?

My post from a couple weeks back indicated that NodeBB started following part of FEP-7888: Demystifying the context property.

Our implementation is an endorsement of @trwnh@mastodon.social's proposal that the context property be given additional formalization.

During the last ForumWG call, they intentionally (or perhaps unintentionally) summarized their desire that implementors should "just use collections", and that that would be a good starting point for future iteration.

With the current state of context being "there is no coordinated usage of context", this topic aims to provide a snapshot of implementors' use of that property (or lack thereof), and to stimulate further discussion on potential use cases.

Note that this is not the first time the question has been raised. trwnh's discussion topic contained one such summary of current implementations.

As per that topic:

  • Mastodon — does not use context, but provides an ostatus:conversation property
  • Pleroma/Akkoma — uses context, but the url provided is unresolvable, likely used similarly to Mastodon
  • Streams (@mikedev@fediversity.site) — uses context, resolves to an OrderedCollection containing all activities encontered (Creates, Updates, etc.)

My hope is that a provided context resolving to a Collection (or subtype thereof) would allow for proactive topic backfill, instead of relying on reply chain traversal, which while workable, has some rather specific downsides.

As mentioned per the above linked announcement that NodeBB was following FEP-7888:

  • We attach context to all Note objects (NodeBB posts), and it resolves to an OrderedCollection that contains the uris to the other objects in the context (the NodeBB topic).
2 Likes

One thing to mention about context is that there are a few somewhat open questions about its usage:

  • Does it contain objects or activities?
  • If it contains activities, does it contain Creates or also other activities (Like, Announce, etc)?
  • What is the ordering?

These kinds of questions are rather freeform because it’s somewhat up to implementers to make a decision about that.

I personally think it should be just the objects, as I’m not convinced it’s particularly important to have a complete backfilled view of every single like and share, or being able to construct an edit log with every single Create/Update. From the point of view of a casual consumer, that information can be lazy-loaded through checking the likes or shares collection; an optimization would be for the producer to partially embed a representation of those collections with a totalItems and maybe the first page, in order to support a “x, y, and 8 others liked this post” type of UX. But this is a matter of preference; “object or activity” is a longer-standing philosophical debate, as much as is “what makes a conversation”. For the maintainer of a context, it might make sense to say “be prepared to support heterogeneous collections of both objects and activities”, as the sender might attach the context to the object, the activity, or both. In theory, if you receive a Create Note with context attached to both, you might expect that both of them will be contained in the (implicit) grouping. But for maintaining an explicit collection, you kind of get to choose how to go about that. Again, I’m a little wary of placing mandates and restrictions on this, in fear of getting it "wrong* and shutting the door on some implementers.

I also think the ordering should be forward chronological instead of reverse chronological, but this is part of a larger issue with collections ordering and paging: Stricter specifications for pagination of Collections and OrderedCollections (btw, the assertion that “every OrderedCollection MUST be reverse chronological” has been somewhat recently clarified/relaxed to only the ones introduced in activitypub as OrderedCollection) – the ideal would be to be able to, as a consumer, request the collection with parameters for ordering, page size, and start index. But failing that, we could just fall back to a similar requirement of reverse chronology… although I dislike and hesitate to enforce this as a MUST. (The ship may have already sailed for this, but I likewise wish/think that the activitypub OrderedCollections were forward chronological instead of reverse chronological. there’s something conceptually backwards about the whole thing.)

1 Like

@julian I'm not using context, but I think FEP-7888 is great and I want to implement it in the future. Haven't decided yet on what exactly this collection should contain. Slightly in favor of collection of activities (as in Streams / Conversation Containers).

@trwnh @mikedev

1 Like

@silverpill@mitra.social @trwnh@socialhub.activitypub.rocks if the collection contains the entire activity log pertaining to the context, then it makes it harder to determine whether a given object is contained in the collection (as @jenniferplusplus@hachyderm.io mentioned in another thread). If you see a Create(Note) you can't be certain it doesn't get Delete(Note)'d later on in the collection!

1 Like

Thanks for starting this topic @devnull, I’ll add Discourse’s approach soon.

I agree with this, as a baseline. I think there might be a useful distinction here between MUST and MAY. It is necessary for the context collection to contain the base objects. It may be useful for the collection to contain other things for specific cases. For example, if I’m looking at Discourse to Discourse federation, I probably want to have the Likes in there. Perhaps if we establish that context collections will include the objects, and may include other things, if an implementation doesn’t want to support those other things, they can filter appropriately.

I agree with you, and did when I first read your topic on this, however I don’t think we can intentionally violate the published spec, as it will lead to confusion (the solution will be worse than the problem). We have to work with it, or perhaps get it changed (if possible). But I agree with all of the spec-compliant recommendations you have in that topic.

True, albeit there might be circumstances in which you want to know there was a Note, but it has now been deleted. Like with receiving Activities to your inbox, I think we need to support both standalone Notes, and Notes wrapped in Activities. Standalone Notes as the “baseline”, but accommodating the fact that Activity wrapping may occur.

1 Like

To be clear I’m not saying that we should produce outbox/inbox/followers/following/liked/likes/shares as anything other than reverse chronological for now. Merely that we should not lock ourselves into this for other OrderedCollection instances going forward. So for example, we may decide conventionally that the context should be an OrderedCollection that is ordered forward-chronologically and consists of the objects rather than the activities. There’s some wiggle room there depending on what implementers think is most appropriate; as you mention, Discourse may wish to include Like activities as part of the conversation (although I still think it probably shouldn’t). This mainly comes down to two aspects:

  • The actor participating in the context gets to choose whether to attach the context to the object, the activity, or both.
  • The actor maintaining the context collection gets to choose whether to add the object, activity, or both.

As far as recommended behavior, again, if we assume it makes sense to maintain a collection of post objects rather than of activities, then conventionally we ask implementers to attach the context property to the object instead of to the activity. Just be prepared to encounter different cases.^1

^1: expanding on this a little more, there is a certain philosophy that activities are actions that manipulate “post” objects, and there is a different philosophy that takes activities to be the primary “post”. I’d say that the former is more rooted in AS2 while the latter is more rooted in AP; AP expects activities in more places in general.

1 Like

Could you elaborate specifically on why you think Like activities shouldn’t be included?

I would say that you don’t necessarily need one to be primary. Both can be relevant. What people do in a topic can be just as relevant as what people say in a topic.

To give a small example, if I were to make a new topic in Threadiverse Working Group about Discourse’s approach to HTML parsing, a Like from @devnull on that post is arguably more relevant to the topic than if a completely new user, unconnected to the Working Group came along and posted

Hey guys, maybe the wrong place to post this, but I don’t understand HTML! halp!

That Note is arguably less “relevant” than Julian’s Like.

I’m not saying that Activities are primary over Objects, just that both may be relevant depending on the context. I don’t particularly see the benefit in preferencing one over the other in a normative sense. That said, I do think that Objects are necessary as a baseline, as not all implementations will have the same feature set (some may not support likes for instance), so my view on this is a baseline of utility with support for additional, potentially relevant, content:

  1. The baseline to give the context collection utility is the presence of Objects; however
  2. Activities in the collection MAY be just as relevant in certain contexts and should be supported.

Mainly because this information is available via likes “already”. I’m not adamantly opposed to including e.g. Like and Announce in a representation of the conversation, but this needs to be considered more carefully as to whether it’s appropriate or not.

That point was less about “feature set” or “relevance”, and more about e.g. “should the object always be wrapped in a Create or not?” – this was discussed in an earlier topic about “Implicit Creates”: Implicit Creates – and the answer is “it depends on the convention you’re following”. A practical example would be how Streams includes the Create activity, while NodeBB includes the object. It’s not like either of these usages is more “correct” than the other. It’s just a difference in opinion.

Put another way: You can have a collection of Creates and Likes, or Notes and Likes, or just Notes, or Creates/Likes/Announces, or so on and so forth. There’s only so much you can actually constrain here; constraining too much would end up being detrimental to certain use cases.

1 Like

If context contains ordered activities, servers can easily sync their copies of context by fetching the collection until they encounter activity with a certain timestamp. That could be useful for backfilling in federated groups.
If context contains objects, backfilling would be limited to comments (no reaction backfilling, which can be important for Reddit-like services).

1 Like

I have created a spreadsheet with open editing permissions (for now) and invite implementors to add their implementations if applicable.

One thing I am noticing now (and should've expected) is that not every software has the concept of a discrete context, nor can you expect one from remote activities. In those scenarios, the fallback seems to be to point to the root-node Object and iterate via replies collection.

For example:

  • @mariusor@metalhead.club's FedBOX defines context as the root-node Object.
  • @mikedev@fediversity.site's (streams) has a concept of conversation containers, and if context is received, inherits it, but otherwise, context becomes the root-node Object.

@trwnh@mastodon.social does FEP-7888 account for this use-case?

Option 3: context is heterogeneous and can contain both objects and activities.

Or, rather, I should jump to the end of the reasoning chain and just go ahead and say it: if the context is an actor, you can put the “post” objects in context and stuff the full activities in outbox instead. You could even make context be forward-chronological and outbox be reverse-chronological. Fetching context means fetching the “posts” of the thread; fetching outbox means fetching the “activity log” of the thread.

The way you make that work is inbox forwarding. The reason FEP-7888 makes mention of context.followers “if the context is an actor” is entirely due to this possibility. Your participatory activity looks something like this:

id: <some-create>
actor: <you>
type: Create
object:
  - id: <your-object>
    content: "Hello to the everyone"
    context: <context>
to/cc/audience: <context>, <context/followers>, <as:Public>

This indicates that the object should be Added to the <context>. You could also/instead attach context to the activity, but you don’t need to do that if you instead rely on inbox forwarding:

id: <some-like>
actor: <someone>
type: Like
object: <your-object>
to: <you>  # this notifies you directly/actively
cc: <context>, <context/followers>  # this means it will be delivered to the context actor to be forwarded to its followers

You wouldn’t need to Add the <some-like> to the <context> if you instead forward it and also make it available via <outbox>.

Again, adding to context collections is a bit of a negotiation between the sender and receiver. The sender adds the context property in the hopes that the receiver will Add that object (which may be an activity) to the context collection. The receiver is free to not Add the object/activity. Just like the receiver is free to not forward the activity to its followers, if it is deemed spam. But assuming all goes well, the ideal situation is that the post object gets labeled with the context property and added to the context collection, while the activity is inbox-forwarded to the context’s followers and/or audience.

1 Like

There’s three possibilities laid out in FEP-7888 regarding the use of context:

  • It’s missing. Fall back to other heuristics (inReplyTo, etc) to do implicit grouping.
  • It’s a non-dereferenceable URI. Do explicit grouping against this URI.
  • It’s a dereferenceable object. Do explicit grouping against the ID, and also:
    • if it is a Collection/OrderedCollection and has attributedTo, you can assume that attributedTo will be maintaining the collection; in such a case, you can opt into the rest of FEP-7888 by sending your participatory activity to the attributedTo actor and also audience/followers if present.

With that said, the use of the “root-node Object” as context is supported, but not recommended. It represents a sort of halfway-point where you probably have an attributedTo that can moderate the conversation, but there isn’t an explicit representation of the conversation via items/orderedItems/outbox. The authority of the attributedTo to moderate downstream replies is not clearly established anywhere, hence it not being a great idea to do this.

2 Likes

@trwnh I really like this. Very clean.

@julian @mariusor @mikedev @trwnh At first I thought you were talking about the "@context", used for JSON-LD...

@Julian yeah that's a good point - I think tag would work but I always got the impression that they were more of a micro-level part of a specific piece of content vs. macro-level (being the place they're being discussed in). context would be set at the forum level (whatever the forum's owner specified) whereas tags might be decided by the user. So in that sense, context would more about origination of a post.

Example might be something like this -

{
  id: "https://yuforium.com/forums/cars",
  type: "Service",
  name: "Example Forum About Cars",
  context: "https://another-instance.org/topic/cars"
}

Where a POST to that forum's outbox with a Note would result in that note's context defaulting to the one set to the forum. Posting with another context would result in an error. This makes things a little different than a tag which is what would be user specified. In that sense, context is more about where the post was created, vs. what it was created about. In a federated system, where could be an authoritative entity that encompasses multiple instances and is dereferenceable, or where could be defined as a UUID and be completely unauthoritative and ephemeral.

Given that it's more about the origination of the post, I would agree that the term "Community" is better in this case to define what context relates (instead of "Topic") so in the example, context could be switched to https://another-instance.org/community/cars.

It's been a while since I wrote that up, and at the time I was considering using "Community" as the terminology for a context so I might update that soon (especially with "Topic" being a frequently used convention in forums meaning something totally different).

In the Activity Streams docs, the one part about context that got my attention was this - "An example could be all activities relating to a common project or event", meaning that context exists outside of the scope of what a thread would be, and is more indicative of a forum level or federation setting vs. the contents (objects, activities, etc.) of a single thread.

One context-related issue I’ve encountered which hasn’t been canvased yet, is that context could be used to set the canonical url of a forum topic. When I say I’ve encountered this issue, it’s some feedback we’ve received on the plugin. See further

And the subsequent discussion.

What I’m currently thinking is the following:

  1. When working with a topic (thread etc)
  2. If a Note in that topic has a resolvable context
  3. If the context resolves to a Collection.
  4. Use a resolvable URL for the Collection as the canonical url
    • My current candidate for a “resolvable url” is the url property of the Collection as the Discourse plugin already serializes the topic url as the url of Topic Collections.

Interested in thoughts on any of the above.

Sounds reasonable to me

1 Like

re:

Use a resolvable URL for the Collection as the canonical url

Angus, it's a little more complicated than that I think. Two concerns:

  1. It depends on where the topic first started. If a topic started on i.e. SocialHub then it makes sense that the canonical URL should be SocialHub. If it started on the NodeBB community it should be that. This might've been implied in your post, but I wanted to make sure!
  2. Secondly, it would not be correct to set a resolvable context as the canonical URL if that context resolves to an AP implementer following FEP 400e, unless you also keep track of whether all items in that context were Add'd and can confirm that all items are in that collection.
    • Short of that it's easier to just maintain your own context and canonical URL. That's this line in 7888:
      • You MAY set your own context, if you wish for your object to be in a separate context owned by you.

cc @trwnh@mastodon.social

Also sorry for the delay, it turns out I introduced a regression that caused replies to not make it into NodeBB for the past 12 days. Yikes.

So until that second point is considered — maybe we should discuss at next ForumWG meeting... — I might just maintain my own set of known contexts local context, and send additional <link rel="alternate" type="application/activity+json" href="//..."> instead

In AP, I was considering sending an Array in context if applicable, with my context first, and all others afterwards.

Happy to do it your way, but would need to resolve that 400e problem first.

I might have not phrased that clearly enough – there is a soft assumption in 7888 that there is only one context set, especially when reading those bullet points. In other words, you would be overwriting the one context with another. This is the same as “starting a new thread” or “forking the topic”.

At the same time, it should be possible for context collections to have multiple identifiers – id being “canonical” and aliases being present in alsoKnownAs. I feel like having multiple collections for the same topic is not a good way forward; it’s better to look at it as a state synchronization problem instead, with one collection at the origin being the source of truth. You maintain a local cache of that collection.

2 Likes