FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea)
from julian@community.nodebb.org to swicg-threadiverse-wg@community.nodebb.org on 18 Oct 18:15
https://community.nodebb.org/post/101472

Related to the ForumWG topic of resolvable context collections, there are four FEPs that are currently in consideration:

  1. FEP-7888: Demystifying the context property
  2. FEP-400e: Publicly-appendable ActivityPub collections
  3. Draft FEP-171b: Conversation Containers, an evolution of Conversation Containers
  4. FEP-76ea: Conversation Threads

@silverpill@mitra.social made a suggestion last month to hopefully reduce the number of moving parts:

  • Both FEP-400e and FEP-1b12 implementations: support FEP-7888 (context collection)
  • FEP-400e implementations: upgrade to Conversation Containers
  • FEP-1b12 implementations: add target property to Announce activity that points to context collection.

This takes FEP 400e out of the running (potentially). But the day after that last meeting, @evan@cosocial.ca put together FEP 76ea, and now we're back to three.

My concern is that all three FEPs (7888, 171b, and 76ea) all share these distinct qualities:

They differ on the following qualities:

In the lead up to the November WG meeting I'd like to address those differences. All three FEPs are in pre-draft or draft stages, and so I am hoping we can find some common ground and compromise.


Pinging interested parties (who were not already mentioned above) for comment:

@trwnh@socialhub.activitypub.rocks @erincandescent@akko.erincandescent.net @mikedev@fediversity.site @jenniferplusplus@hachyderm.io

#activitypub #forumwg #swicg #swicg-threadiverse-wg

threaded - newest

jenniferplusplus@hachyderm.io on 18 Oct 18:39 next collapse

@julian @silverpill @evan @trwnh @erincandescent @mikedev
I continue to feel that this general idea is in keeping with the as-written intent of the context property. Adding a new property is likely to make adoption slower and more complicated. Adding a new object type is also likely to make adoption slower and more complicated, but less so than the property. Either of those option only really makes sense to disambiguate from existing uses, of which there is very little.

jenniferplusplus@hachyderm.io on 18 Oct 19:17 collapse

@julian @silverpill @evan @trwnh @erincandescent @mikedev
As a side note, it's beyond frustrating that the original goal of this topic was to accomplish reply-limiting controls. But, a year and a half later, we're still bike shedding data types and haven't even gotten to the point of talking about an actual behavioral protocol for proposing, accepting, rejecting, and verifying the addition of an object to a relevant collection.

julian@community.nodebb.org on 18 Oct 20:24 collapse

@jenniferplusplus@hachyderm.io said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

As a side note, it's beyond frustrating that the original goal of this topic was to accomplish reply-limiting controls.

I understand your frustrations, and for what it's worth, I feel like we need to get the more basic expectations out of the way first, that is: how do we meaningfully assign context to a set of individual posts, besides the already available but fragile inReplyTo traversal?

At the same time, I do think that all four FEPs mentioned utilise the same mechanism for establishing basic reply-limiting... that there is a context owner that ultimately decides whether a reply is added to the collection or not.

silverpill@mitra.social on 18 Oct 18:51 next collapse

@julian @evan @jenniferplusplus @mikedev @erincandescent @evan @trwnh

>7888/171b use context whereas 76ea uses a new property thr:thread

I think context is good enough. Streams and NodeBB already provide this collection and Mitra will too.

>171b specifies a new object type Context

It is for easier identification of conversation-Add activities. My server may receive many different kinds of Add activities, and it would be nice to have some indication of what collection is being modified.

This is just an idea though. Streams uses Collection type

>Collection items:

My use case requires items to be activities, but I can support both variants of context collection. Conversation activities can be also put into a different collection.

julian@community.nodebb.org on 18 Oct 19:01 next collapse

@silverpill@mitra.social said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

It is for easier identification of conversation-Add activities. My server may receive many different kinds of Add activities, and it would be nice to have some indication of what collection is being modified.

In that case, are you trying to sidestep a potential future conflict? I think I can see your rationale that duck typing "resolved context is a Collection" may not be specific enough, but I am not currently aware of anybody outside of 400e/7888 that has a context that even resolves to anything.

silverpill@mitra.social on 18 Oct 19:57 collapse

@julian

No, that's for target property. Here's an example of Add.target from Streams:

"target": {
  "id": "https://streams.lndo.site/conversation/ed4775f8-18ee-46a5-821e-b2ed2dc546e8",
  "type": "Collection",
  "attributedTo": "https://streams.lndo.site/channel/red"
},

In my code I have a handler for Add activity, which then sends activity to one of the other handlers:

- Add{target: featured}
- Add{target: subscribers}
- Add{target: context}

Currently I use heuristics to determine which one to use. But with Add.target.type == <meaningful type name> the code would be simpler and less fragile.

Do you have something like that in NodeBB? I wonder how others solve this "routing" problem

julian@community.nodebb.org on 18 Oct 20:33 collapse

@silverpill@mitra.social said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

Do you have something like that in NodeBB? I wonder how others solve this "routing" problem

We do the same. We don't actually handle Adds right now, but our Update handler has a switch..case based on type.

Adding a separate type would be easier, yes. Otherwise you're looking at additional logic to tease apart different variants that share the same base object type. For example, the logic for Update(Note) has further logic paths depending on whether the note is publicly addressed or not.

So then yes, a Add{target: Collectionish} might be vague, but that's only the case if other implementations use the same.

silverpill@mitra.social on 18 Oct 22:58 collapse

@julian This pattern can also be used in Accept and Undo activities:

{
  "type": "Undo",
  "id": "https://social.example/activities/undo/1"
  "object": {
    "type": "Like",    # or "Follow"
    "id": "https://social.example/activities/like/1"
  }
}
erincandescent@akko.erincandescent.net on 18 Oct 19:07 collapse

@silverpill @julian @evan @evan @mikedev @jenniferplusplus @trwnh

My plan is to bring Akkoma into conformance with FEP-7888. Contexts (as they implicitly exist) contain Objects in Akkoma today, and my plan is to make that collection dereferencable.

At the moment I have no plan to implement sending of Add activities though that could come in the future.

Regarding FEP-171B’s use of the Context object type, I am ambivalent. We will likely expose an (Ordered?) collection at first.

FEP-76EA’s definition of thr:thread doesn’t match how Akkoma maintains or interprets the Context today. My opinion is that I would only invest time in implementing it if implemetations actually coalesced around it; it doesn’t suit our needs. In particular the requirement “The tree structure of the thread should be maintained; every object in the thread collection, except the root, should have an inReplyTo property that matches the id of another object in the collection.” does not match how Akkoma handles quote posts (it places them in the same Context).

julian@community.nodebb.org on 18 Oct 19:13 collapse

@erincandescent@akko.erincandescent.net Future discussions of the ForumWG may turn to more forum-like handling of context collections like forking, moving of posts, locking, pinning, etc.

In the former two cases, inReplyTo would no longer necessarily point to an object that is in the self-defined context collection. This is a very good point.

@trwnh@mastodon.social also made this point recently as well.

mikedev@fediversity.site on 18 Oct 19:13 next collapse

Conversation containers does send a 'Remove' if something is removed from a collection. But we typically don't waste resources on spammers, so we don't necessarily send a 'Remove' if we decided not to add it in the first place (perhaps due to comment controls, permissions, or blocks). You can send these as Remove activities if you want, but please don't force me to do so.

If you've fetched a conversation collection, it would be most common to do so in order to cache the conversation locally. In this case storing under local entities is going to be much more efficient if parents are stored before their children, so the InReplyTo can be pointed to an existing stored entity. If you do it backward, it's kind of awkward.

That said, our implementation of Collection objects has a flag to reverse the returned item order. So as long as the order is defined and isn't going to change, I don't actually care what it is; beyond the storage efficiency mentioned above. We need to sort it how we want after fetch anyway, because that's just basic input sanitisation.

It would seem most natural to me to send the collection in "thread" order - start from the root and recursively traverse every branch/leaf encountered. I'll mention this for consideration -- but again I really don't care.

trwnh@mastodon.social on 19 Oct 00:51 collapse

@mikedev @julian you shouldn't have to send a Remove if you never Added it.

i also agree that the order should generally be forward-chrono because fetching the context in a linked data browser should render the context in the same way that the HTML view would render it by default. i don't know anyone who reads threads backwards.

in any case i recently submitted https://w3id.org/fep/1985 for explicitly declaring an `orderType` for OrderedCollection

trwnh@mastodon.social on 19 Oct 00:58 collapse

@mikedev @julian i am also thinking about extended OrderedCollection to specifically represent *sorted* sets and not just *ordered* sets. that fep would define `sortedBy` pointing to a vocab term, as well as `sortType` being either `Ascending` or `Descending`. the only thing that gives me pause is that people can lie about the value of their object's sorting property, for example setting an as:published in the distant past to be pinned to the beginning of the SortedCollection.

julian@community.nodebb.org on 19 Oct 01:48 collapse

@trwnh@mastodon.social @mikedev@fediversity.site I think end of the day it's an implementation detail that is of minimal significance. When I fetch the collection pages I don't trust the order anyway, I reorder them all by date once I have them all anyways.

@silverpill@mitra.social said that reverse chrono for activities is preferable, and that makes sense if you want to sync up. Just retrieve activities until you reach one you've seen and you're caught up.

trwnh@mastodon.social on 19 Oct 01:55 next collapse

@julian @mikedev @silverpill i generally agree that seeing newest activities is usually preferable , but you could just as easily traverse as:last/as:prev* and stop when you reach something you've already seen, instead of traversing as:first/as:next* and likewise stopping when you reach something you've already seen. it's never made sense to me to mandate reversed order when it should just be the "recommended default". i think the real issue is that OrderedCollection doesn't imply any real order

scott@authorship.studio on 19 Oct 19:25 collapse

@julian

reverse chrono for activities is preferable, and that makes sense if you want to sync up. Just retrieve activities until you reach one you've seen and you're caught up.

I wouldn't necessarily trust that. I have seen too many instances of incomplete threads being saved locally, and having to go to the source website to see the whole thread. These missing posts can be a pain, because unless the website supports OpenWebAuth, you can't reply to a comment that was not saved locally on your server.
trwnh@mastodon.social on 19 Oct 01:48 next collapse

@julian i replied from socialhub but it seems to not have made it across yet... again :x https://socialhub.activitypub.rocks/t/fep-convergence-400e-7888-171b-conversation-containers-76ea/4669/12

evan@cosocial.ca on 19 Oct 12:46 next collapse

@julian @silverpill @trwnh @erincandescent @mikedev @jenniferplusplus@hachyderm.io obviously `context` isn't good enough to identify the thread relationship. Trying to hijack it is contrary to the AS2 spec and common interoperability. One proposal tries to specify it by duck-typing every object; the other by defining a new Collection type. The clearest way to define the relationship is with a property, `thread`, which is specific, clear, and requires no other changes.

evan@cosocial.ca on 19 Oct 12:51 next collapse

@julian @silverpill @trwnh @erincandescent @mikedev I think most developers understand that the reply tree and the conversation are identical. The use cases a describes -- forking, etc. -- can be implemented with `Announce`, perhaps with `content` in the `Announce` activity. I'll add these next week and push a new draft.

evan@cosocial.ca on 19 Oct 13:09 collapse

@julian @silverpill @trwnh @erincandescent @mikedev I think `context` can be used as a fallback, which provides continuity for most of the legacy implementations.

erincandescent@akko.erincandescent.net on 19 Oct 12:52 collapse

@evan @julian @silverpill @trwnh @mikedev "context" isn't good enough to identify any relationship; this is the fundamental problem. It is a property that should never have existed. Today it identifies one relationship: the (loosely defined) thread. I would argue that this is in fact "common interoperability". I would also argue that this fully meets the incredibly vague letter of the ActivityStreams specification.

I have yet to see an alternative use of context that would not be better served by inventing a more specific term. Yes, this applies to use of context for thread too, but we have 7 years of its user to identify the thread as a defacto standard.

trwnh@mastodon.social on 19 Oct 13:05 next collapse

@erincandescent @julian @evan @mikedev @silverpill i don’t think “conversational thread” is a special semantic relationship, and i certainly don’t think it is equal or equivalent to a reply tree! the basis of 7888 is that context should be used for purposeful logical grouping, as it was intended and as it ended up being used in pleroma for years. an unresolvable opaque uri is 7888-compliant. so is a collection with an owner. so is anything else. but IF it is a collection,

trwnh@mastodon.social on 19 Oct 13:09 collapse

@erincandescent @julian @evan @mikedev @silverpill …then it makes sense that the collection ought to contain items sharing the same contextual grouping. it’s similar to how hashtags are content-addressed grouping, but less purposeful, and no one owns them. the key is that even if you can’t resolve anything out of whatever is in context, you can still use it for grouping by opaque string matching. so there’s clearly defined graceful fallback.

trwnh@mastodon.social on 19 Oct 13:17 collapse

@erincandescent @julian @evan @mikedev @silverpill as far as reply trees go, it should be clear that they are not the same as a conversation or context, and inReplyTo exists completely separate and parallel to contextual grouping. the “reply tree” model falls apart the second you reply to multiple things, or reply to something in a different context, or reply and change the context, or set a context but no inReplyTo. i’m not sure why you say Announce has anything to do with it with

evan@cosocial.ca on 20 Oct 04:17 collapse

@trwnh @erincandescent @julian @mikedev @silverpill I have an example of a reply to multiple things in the FEP.

"Comment but don't participate in thread" is a quote boost. It also works for forking to a new thread.

So, that's what `Announce` has to do with it.

Conversation threads are *usually* reply trees, and we should optimize for that easy base case. The advanced tree-pruning and -grafting you describe are possible with a reply tree.

trwnh@mastodon.social on 20 Oct 04:41 collapse

@evan @erincandescent @julian @mikedev @silverpill

> Conversation threads are *usually* reply trees

this is an anti-pattern. conversations are only represented by reply trees when there isn't an actual conversation. reply trees are a poor substitute for that.

> "Comment but don't participate in thread" is a quote boost.

i'm talking about participating in a thread without responding explicitly to anything. or responding to something, but in a different thread. no one is boosting anything.

trwnh@mastodon.social on 20 Oct 04:50 next collapse

@evan @erincandescent @julian @mikedev @silverpill boosting, replying, and grouping are three completely separate functions. the Announce could have its own inReplyTo and/or context.

evan@cosocial.ca on 20 Oct 04:58 collapse

@trwnh @erincandescent @julian @mikedev @silverpill

Maybe we need to agree that these two properties are different.

I agree that `context` is great for a related collection of objects, including for a project or event, as defined in AV.

For the specific collection of objects that are members of the same reply tree, we can use `thread`.

If it doesn't matter to specify that it's a thread, you can link to the exact same collection with `context`. It is, after all, also a related collection.

trwnh@mastodon.social on 20 Oct 05:10 collapse

@evan @erincandescent @julian @mikedev @silverpill Sure, it's possible to declare both a `context` being whatever grouping, and a `thread` being specifically a reply tree. (Perhaps `thread` should be renamed to `replyTree`, and `root` should be renamed to `replyTreeRoot`?)

I'm specifically against conflating the two concepts, though. I also would prefer to not give `inReplyTo` any undue deference beyond simply being metadata. For as many systems that rely on it, there are systems that don't.

trwnh@mastodon.social on 20 Oct 05:16 next collapse

@evan @erincandescent @julian @mikedev @silverpill For example, replying to a message is something that the user *explicitly chooses* to do when in the context of image boards or chat rooms. If you've ever used Discord, then you can see how in that system, it wouldn't make any sense to say that every message in a channel necessarily must be inReplyTo some other message in the channel (or anything at all). The room is a bound context.

evan@cosocial.ca on 20 Oct 05:21 next collapse

@trwnh @erincandescent @julian @mikedev @silverpill yes, I absolutely agree that a chat room is topologically different from a forum thread, a Reddit post, or a social network.

evan@cosocial.ca on 20 Oct 05:21 collapse

@trwnh @erincandescent @julian @mikedev @silverpill I would represent a chat room as a `Group`.

trwnh@mastodon.social on 20 Oct 05:26 collapse

@evan @erincandescent @julian @mikedev @silverpill

1) I disagree; chat rooms, forum threads, comments sections, etc. are all just different presentations of the same generic data structure (objects in collections). I could pull the AS2 data for this entire chain of replies and render it as a chat room, or as a messenger, or however I wanted to -- flat chronological list or otherwise.

2) I would use `Group` to represent an actual group of agents. For a group of posts, I would use Collection.

evan@cosocial.ca on 20 Oct 06:09 collapse

@trwnh @erincandescent @julian @mikedev @silverpill yes. The members of the chat room are the group. Posting to the group shares to everyone. There's a concept of joining and leaving the group.

trwnh@mastodon.social on 20 Oct 06:23 collapse

@evan @erincandescent @julian @mikedev @silverpill Multiple collections (or any object type) can exist while sharing the same group of agents (or any other non-group set of agents) as an audience. It's not correct to say that a room "is" the group, unless you want everyone to manually join every single room one-at-a-time. The audience is the scope to which the posts (or collection of posts) are relevant, similar to how the context is the grouping. https://www.w3.org/TR/activitystreams-vocabulary/#audience-and-context

trwnh@mastodon.social on 20 Oct 06:27 next collapse

@evan @erincandescent @julian @mikedev @silverpill historical evidence that is also relevant here:

https://github.com/w3c/activitystreams/issues/300

https://github.com/w3c/activitystreams/issues/238#issuecomment-153408442

evan@cosocial.ca on 20 Oct 08:45 collapse

@trwnh @erincandescent @julian @mikedev @silverpill yes, `scope` became `audience` and was (incorrectly, I think) made into an addressing property in AP.

evan@cosocial.ca on 20 Oct 08:37 collapse

@trwnh @erincandescent @julian @mikedev @silverpill

> [...] unless you want everyone to manually join every single room one-at-a-time.

This has always been my experience with chat rooms. People join (or enter) the room, make posts to the room that are visible to everyone "in" the room, and some time -- maybe years later -- leave the room.

Regardless: groups and threads are not the same thing.

trwnh@mastodon.social on 20 Oct 08:51 next collapse

@evan @erincandescent @julian @mikedev @silverpill Joining a Discord guild (the Group, loosely) gives you access to multiple rooms/channels (a bunch of Collections) all at the same time. Each channel could be rendered as a chat room or as a forum thread or however you want to display a collection of objects.

Essentially, `audience` and `context` are converse properties. In many cases, the "group" is the `audience` and the "thread" is the `context`. This is emergent behavior in NodeBB/Discourse.

trwnh@mastodon.social on 20 Oct 08:56 next collapse

@evan @erincandescent @julian @mikedev @silverpill I suppose it could be complicated a bit when you start to consider rooms/channels/threads/topics/etc that are limited to a subset of the group/audience, for example via a roles system. But that's something I don't want to think about yet; at least not until we have a foundation that works for representing posts and contexts and audiences

evan@cosocial.ca on 20 Oct 18:47 collapse

@trwnh @erincandescent @julian @mikedev @silverpill so, is the Forums WG for making a federated Discord? I thought it was for forums and threaded news.

I'm glad there are other interesting social systems to model. I think you are mistaken that one size will fit all.

trwnh@mastodon.social on 21 Oct 00:29 collapse

@evan @erincandescent @julian @mikedev @silverpill If we disagree, we disagree; but my understanding developed over the past several years of thinking about this is that generic data can be presented in multiple specific ways. The UI may change, but the semantics stay the same. There are already apps that will show you your timeline as a chat messenger UI, or your conversation as a flat chronological list instead of chopped-off reply tree branches. Are they wrong?

evan@cosocial.ca on 21 Oct 07:12 collapse

@trwnh @erincandescent @julian @mikedev @silverpill You haven't been thinking about this problem nearly as long as I have. Who do you think created `ostatus:conversation`?

Anyway, I think we agree on more than we disagree on. We both think `context` should be for general groupings.

We both think the thread identifier should be a dereferenceable collection, and that the original post creator should emit `Add` activities to show that it's been updated.

evan@cosocial.ca on 21 Oct 07:15 collapse

@trwnh @erincandescent @julian @mikedev @silverpill I think the reply tree is essential and should have its own property so it's easy to find and use, rather than having to guess if what's in the `context` collection is a reply tree. You don't; that's too bad.

trwnh@mastodon.social on 21 Oct 13:06 collapse

@evan @erincandescent @julian @mikedev @silverpill It’s not about how long one thinks about it, moreso that this idea of “generic data with specific presentations” didn’t come out of nowhere overnight. We shouldn’t overfit our data model to any specific presentation. It would be a great shame to continue privileging inReplyTo above other metadata; it represents a form of context collapse, because responding to something shouldn’t be a stand-in for an actual conversation.

trwnh@mastodon.social on 21 Oct 13:13 collapse

@evan @erincandescent @julian @mikedev @silverpill Basically, I’ve seen and directly experienced so many cases where a conversation is not and should not be the same as a reply tree, and where conflating the two has created problems on conceptual, technical, and social layers. They exist separately, and have different semantic properties. Consider that someone making a post inReplyTo something else may not actually be participating in the same conversation, or any at all!

scott@authorship.studio on 22 Oct 05:22 next collapse

@infinite love ⴳ @Evan Prodromou This is exactly why platforms that have threads should declare that it is a thread. The reply tree does not always indicate whether it is a thread.

If the reply belongs in a conversation container, the container should be mentioned via ActivityPub. That way the receiving platform can display it properly.

(Thread = Conversation = Conversation Container & its Posts)

julian@community.nodebb.org on 22 Oct 16:08 collapse

@trwnh@mastodon.social @evan@cosocial.ca I have the feeling we're getting too into the woods about defining what exactly a thread or context ought to contain and specifying that those definitions need to persist across all implementations.

I don't think they have to.

NodeBB considers a conversational context as a "topic"/"thread". ForumWG decided to refer to these as "contexts" for ease of discussion, but other software need not follow that paradigm.

If one implementor decided to utilise context to contain only one specific line of objects (a "sacred timeline thread", if you will), I'd argue that's a perfectly valid use of context, and also fits into the definition of both of your FEPs. When they pull a NodeBB context they'll get what NodeBB thinks is a context (the entire reply tree), and that's okay too.

Basically, my argument is that yeah, as Evan said:

Anyway, I think we agree on more than we disagree on.

When we step back and think about what we want to achieve:

  1. Ability to reliably backfill a conversational context
  2. Declare a context owner that acts as a canonical source for context additions/removals (reply limiting and such)

Then what we're left with are three FEPs (7888, 171b, 763a) that all fit the bill but only differ in minor technical aspects.

julian@community.nodebb.org on 22 Oct 16:14 next collapse

If we're going to talk about favouring FEPs over minor technical aspects, need I remind you of the following from @jenniferplusplus@hachyderm.io:

I continue to feel that this general idea is in keeping with the as-written intent of the context property. Adding a new property is likely to make adoption slower and more complicated. Adding a new object type is also likely to make adoption slower and more complicated, but less so than the property.

The more complicated you make something, the fewer implementors you're going to get. I haven't thought about these concepts nearly as long as you two have, but especially when you're talking about volunteer developers who have to work with other volunteer developers, any stumbling blocks could become insurmountable.

Simply put: there's a reason when someone wants to use OAuth2 SSO on NodeBB it's a free plugin, and when they want to hook into their corporate SAML SSO I charge a rather hefty sum.

@trwnh@mastodon.social @evan@cosocial.ca

evan@cosocial.ca on 22 Oct 18:52 collapse

@julian I think including the thread in the `context` property is fine; I think saying that the only thing that should go in `context` is the thread is not OK.

If you're concerned about simplicity, having a clear property to use only for the thread is the way to go.

julian@community.nodebb.org on 22 Oct 20:40 collapse

@evan@cosocial.ca in that case if @trwnh@mastodon.social were to relax their restrictions on what context can contain to include both conversational contexts and reply trees, would that be sufficient?

trwnh@mastodon.social on 22 Oct 23:51 collapse

@julian @evan That restriction doesn’t exist; technically the collection contains whatever the owner adds to it. Putting `context` on your object is no guarantee your object will end up in there. Neither will `inReplyTo`.

`context` should be used for grouping, but specifically for a *purposeful* grouping. At its base, it’s like a fancy hashtag, but instead of being a simple reference, it imparts meaning and understanding when you consider the object “in context of” it.

trwnh@mastodon.social on 22 Oct 23:57 collapse

@julian @evan The problem is in social expectations. If I send you an object from a generic AP server that declares “inReplyTo” but a different “context”, it would violate my expectation for that object to end up in a different topic than the one i asked to be included in. But sending it from Mastodon, the calculus changes: Mastodon currently doesn’t support the concept of a reified thread as separate from the reply tree, so NodeBB including that post would be a fallback.

trwnh@mastodon.social on 23 Oct 00:06 collapse

@julian @evan So the ideal would be signaling on the actor (or jumping ahead in theoretical developments, on the client attached to the actor) that a certain protocol is being followed. That way you don’t have to make guesses and uncertain assumptions.

And then I would ideally be able to send you an object for consideration to include in some collection. It seems reasonable to say that me declaring one of your contexts should be the primary consideration for inclusion.

trwnh@mastodon.social on 23 Oct 00:11 collapse

@julian @evan But as Evan points out:

> saying that the only thing that should go in `context` is the thread is not OK.

It is possible that any given context may be a Person, or an Event, or a Location, or whatever. (This probably makes more sense in a GTD tasks app than in a forum software.)

It’s also possible it may be an opaque URI.

Nevertheless, if you can’t extract any useful information from it, you drop it from consideration. No owner means no one to address.

trwnh@mastodon.social on 23 Oct 00:17 next collapse

@julian @evan What 7888 tries to do is describe a potential generic framework for how to process objects declaring a `context`, all the way up from the base case (missing) to the simplest case (an opaque URI) and building upwards from there. This is similar to how you might process objects declaring a `tag` array to detect rich entities within the textual content of the post (mentions, hashtags, links, potentially quotes, emojis, whatever the future brings)

trwnh@mastodon.social on 23 Oct 00:31 collapse

@julian @evan The “missing bit” is a signal for participation; in other words, a property and/or type that means “if i send an object matching a certain shape to the owner, they might add it to this collection.” Right now this is implicit; it would be better if it were explicit.

scott@authorship.studio on 23 Oct 13:06 collapse

@infinite love ⴳ @Evan Prodromou @julian I am working on a fediverse-enabled project management system. And this discussion is very relevant to it, since we are talking about what are contexts and whether they are the same as threads.

Scenario:

Project is an actor.
Forum attached to the project is also an actor.
You can follow both, but one provides updates about the project and the other is a discussion group.

Posts related to the project will have the context set to that project. But that project is not a conversation. The thread is a conversation.  And there will be multiple threads related to the context.

If we declare that the post has two contexts, how would you know which one is the thread?

This is why I think there needs to be a clear property that defines a thread.

julian@community.nodebb.org on 23 Oct 15:06 collapse

@scott@authorship.studio said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

Posts related to the project will have the context set to that project. But that project is not a conversation. The thread is a conversation. And there will be multiple threads related to the context.

If we declare that the post has two contexts, how would you know which one is the thread?

If in your system a single post can be both a response to the project and a response to a thread, and you wish to provide two contexts, then put the more specific context first (the thread), followed by successively less specific contexts (the project).

Implementors that don't support your structure will simply use the first context in the list by assuming it's the most specific.

scott@authorship.studio on 24 Oct 04:30 next collapse

@julian

If in your system a single post can be both a response to the project and a response to a thread, and you wish to provide two contexts, then put the more specific context first (the thread), followed by successively less specific contexts (the project).

Implementors that don't support your structure will simply use the first context in the list by assuming it's the most specific.

That's a good fallback behavior, but there still should be a way to explicitly declare which is the thread for platforms that support it.
trwnh@mastodon.social on 24 Oct 08:45 collapse

@julian @scott to start with, i don’t think it’s necessarily correct to say that the post was created in context of the project; you might want to say that the post was created in context of a discussion topic, which itself exists in context of the project. but it’s up to the post author how they want to declare this.

the other thing is, consider the case where there are two contexts, and they’re *both* threads. by which i mean, all the necessary properties are there. //

trwnh@mastodon.social on 24 Oct 08:51 collapse

@julian @scott Anyone wanting to respond to that post has the following options:

1) inReplyTo post, context = 1
2) inReplyTo post, context = 2
3) inReplyTo post, context = 1,2
4) inReplyTo post, context = something else (or nothing)

and then they deliver to the owner(s) of whichever context(s) they selected.

Or maybe they don’t want to respond. Maybe they want to participate without specifically responding to anything else in either thread. So they drop inReplyTo. //

trwnh@mastodon.social on 24 Oct 08:54 collapse

@julian @scott anyway, situations with multiple contexts are probably going to be edge cases.

honestly, the most likely outcome will be that implementers will just incorrectly assume a max of 1 context, just like they already incorrectly assume a max of 1 inReplyTo. in this case, the restriction becomes part of the implicit protocol, alongside numerous other stated or unstated restrictions.

trwnh@mastodon.social on 24 Oct 09:00 collapse

@julian @scott in any case, i think based on this conversation i probably need to add examples to fep-7888 of how one might process multiple contexts.

scott@authorship.studio on 25 Oct 16:44 collapse

@infinite love ⴳ @julian @Evan Prodromou So, basically, we are saying that:

Context = Conversation = Thread

because everyone assumes that is the case.

And anything not a thread should probably be something else, like a collection?

Because, at least in every forum implementation I have ever seen, there is only one thread. And like everyone else, we will only support ONE thread.

Therefore it is unnecessary to support multiple threads because nobody plans on supporting it and it goes against 40 years of usage.

But, posts and threads can be associated with other things, like projects, that are NOT a thread, but rather a collection of related posts.

The question is: how do you associate non-threads (like projects) with a threaded conversation?

julian@community.nodebb.org on 25 Oct 17:23 collapse

@scott@authorship.studio I think I know how that one can be solved.

Using Hubzilla nomenclature:

  • When you have a post it defines the thread as context
  • Your post can also define the project as audience as per FEP 1b12
  • The thread (the context collection) would define the project as the collection owner (attributedTo)
scott@authorship.studio on 25 Oct 17:41 collapse

@julian Would an audience be appropriate for a collection of threads & posts?

Also, the project won't be the owner, since any post on our system can be flagged as being associated with one or more projects. It will be a collection of random threads and posts that happen to be related to the project.

The whole idea is that we can tag threads as being related to a project, no matter what forum or channel they came from.

The collection can then be queried and a list of related threads and posts would be provided.

Also, as a side note, the project management system will be headless. One of the heads will be Hubzilla, but we may create a non-Hubzilla based head later.

scott@authorship.studio on 22 Oct 16:55 collapse

@julian How I view it is:

1. What information is being transmitted now?
2. What information do we want to have?

We will always have to deal with implementations that vary, and we sometimes will have to assume things because they did not send all of the information we need.

But, we can still say "we would prefer the information be sent in this format." especially if that format includes additional information that tells us how to render it properly.

So there is a difference between the minimum amount of information we need and what information we want to have.

Or put another way, we can provide a way in the spec to declare that something is a thread, but still be able to process the data without it (by making assumptions since we are missing some of the data).

scott@authorship.studio on 20 Oct 08:58 collapse

@Evan Prodromou To put it another way, there are several levels.

1. Things you can join and follow, such as chat rooms, discussion groups, and forums. It has a membership, and the administrator controls who is a member and who is not. When you join, you automatically follow it.

2. Categorization and curation, such as tags, categories, lists, etc. This can be filtered against by the recipient. Or, if offered, can be followed.

3: Specific conversations, which can include forum threads, Facebook-style threads, direct message conversations, etc. This keeps conversations in a container so they are easier to read.

jenniferplusplus@hachyderm.io on 20 Oct 05:29 collapse

@trwnh @evan @erincandescent @julian @mikedev @silverpill
This conversation is hard to follow, since Evan blocked me for some reason. It makes this a notably bad venue to have these technical discussions with him.

But for what it's worth, I agree with all of your analysis and conclusions on this topic.

evan@cosocial.ca on 20 Oct 05:16 collapse

@trwnh @erincandescent @julian @mikedev @silverpill sounds great.

I'm going to stick with `thread` and `root`.

They're already namespaced, and these are clear terms for these concepts.

Thanks for the help with additional use cases on forking and grafting. I'm going to add some explicit user stories to the FEP and show how each one can be handled.

trwnh@mastodon.social on 20 Oct 05:22 collapse

@evan @erincandescent @julian @mikedev @silverpill One thing to note: If the AS2 context extension policy ever gets adopted and these terms likewise get adopted into the w3.org/ns/activitystreams context document via that process (or any other process), then this creates an issue for any other case where someone wants to use the plain-JSON keys `thread` and `root`.

evan@cosocial.ca on 19 Oct 13:43 collapse

@erincandescent @julian @mikedev @silverpill @trwnh there are other uses called out in the AV spec. Someone using those would clash with the use for threads.

I recognize your aversion to change, but "don't change anything" isn't on the menu. We need a way to identify the thread relationship, and a dedicated property is much better than a duck-typing objects or making a new object type.

evan@cosocial.ca on 19 Oct 13:54 next collapse

@erincandescent @julian @mikedev @silverpill @trwnh we have many orders of magnitude more AS2 objects in our future than in our past. I don't think informal practices of existing software should keep us from implementing better formal systems in the future.

trwnh@mastodon.social on 19 Oct 14:07 collapse

@evan @erincandescent @julian @mikedev @silverpill what is the “thread relationship” and how does it differ from “contextual grouping”?

evan@cosocial.ca on 19 Oct 15:09 next collapse
scott@authorship.studio on 19 Oct 20:14 collapse

@infinite love ⴳ
Three use cases some to mind concerning collections and context:

1. Threaded conversations.
2. Collections of posts.
3. Categorizing posts.

I am not sure if this feature still exists, but I remember when Twitter allowed you to place other people's posts into a publicly sharable list. It was a collection of posts curated by someone, but was not a thread.

I don't know of any fediverse app that currently implements such a thing, but I just wanted to point out that collection and context can be used for things other than threads.

Another use case is placing posts in categories, or place entire threads in categories.

So we probably should explicitly state that something is a thread or conversation... as opposed to a list of random posts on a particular topic.

trwnh@mastodon.social on 20 Oct 04:59 collapse

@scott yes, this can generally be accomplished by defining vocab terms for each type of collection, representing its purpose or classification -- for example, Context / Conversation / MediaAlbum / CuratedMoment / whatever. these are moreso progressive enhancements, though -- if you follow a link, then the link relation is usually enough information to know where you're going, if not necessarily enough to know what you've arrived at. a category is not always a context; context implies purpose.

trwnh@mastodon.social on 20 Oct 05:02 collapse

@scott for example, a blog post is in one or more categories/tags/taxonomies, but the blog post does not exist purely within any of those groupings. generally if something exists in a context, you are less interested in that thing and more interested in the context in which it exists. the context provides a reason or purpose for that object; you can group all objects that share the same context and end up with some cohesive understanding of something.

scott@authorship.studio on 20 Oct 06:23 collapse

@infinite love ⴳ Being able to filter incoming content is just as important as being able to receive it. Providing the categories and the thread would be useful for filtering.

For example, you might have a situation where a particular post may have the following information:

Owner = example.com/@forum
Author (of the post) = example.social/@user
Category = example.com/forum/category/activitypub
Thread = example.com/forum/post/12345

With this information, an inbox can be set up to show threads that are a specific category and ignore the rest. Or ignore certain authors without unfollowing the thread.

In this scenario, you would need to specify which is the thread and which is the category, because the conversation can be pulled from the thread, but not the category.

You can do the same thing with blog posts. Follow a blog, but only see blog posts with specific categories.

trwnh@mastodon.social on 20 Oct 06:36 collapse

@scott Yes, correct. I think that the link relation (or semantic property relation) is what lets you do that. Imagine if instead of context/audience/tag/etc we just had a single property `itemOf` and it was just a grab-bag of every single collection that contained the current object. That wouldn't be very useful! So we use the semantic properties and we can filter against the semantic properties. Simply being in a collection is usually insufficiently semantic -- we need to specify how/why.

trwnh@mastodon.social on 20 Oct 06:40 collapse

@scott Which is to say, an object can have:

- a `context` in which it exists and by which it should be grouped,
- an `audience` to which it is scoped and for which it can be considered relevant
- some `tag` to which it refers

The question is, what does a "category" represent semantically? If the "category" is an actor, then perhaps it is appropriate to say it is part of the `audience`. Otherwise, you might `tag` the "category" instead. Or you might define some other relation.

scott@authorship.studio on 20 Oct 09:13 collapse

@infinite love ⴳ You cannot assume the audience is the same as the category, context, forum, or sender. Some software, such as Hubzilla, has access control. You can set the audience for each individual thread.

Also, what happens when a post has multiple contexts? It is part of a category that you can follow. It was placed in a curated list of posts that you can follow. And it is also part of a thread that is in a forum you can follow. You have three contexts and three actors for the same post.

If you are displaying posts (notes, articles, whatever) as part of a conversation, then knowing which one of those is the thread would be useful.

trwnh@mastodon.social on 20 Oct 09:26 collapse

@scott objects can exist in multiple contexts, same as how an object can be in reply to multiple objects.

The part where I disagree is that not everything needs to be a `context`. A "category" is just a taxonomy, like any tag; the posts exist separately from that taxonomy. A "curated list of posts" is just a Collection, and the posts exist separately from that curated collection.

To figure out what is a context, ask: "does this post make sense on its own?" if no, it exists in some context.

trwnh@mastodon.social on 20 Oct 09:30 collapse

@scott That is to say, the audience/category/context/forum/sender are all separate concepts. It's fine to set an audience for each thread separately. It's also fine to set an audience for each post separately. But if the post is meant to be viewed in the thread, then that thread is serving as a context. "Context" is loosely something that provides reason, purpose, understanding. It's got nothing to do with being in a collection or being followable (although a context MAY be those things.)

scott@authorship.studio on 20 Oct 09:41 collapse

@infinite love ⴳ So, does that mean that context = thread, and nothing else can be a context?

trwnh@mastodon.social on 20 Oct 10:20 collapse

@scott No, a thread is only a context it's declared as an object's context. The context for an object should be something that gives it reason or purpose for existing; processing an object without its context means you aren't fully understanding the object. The context helps you understand that object.

This is generally a "conversation" but not always. Other examples of contextual grouping include a "project" or an "environment".

trwnh@mastodon.social on 20 Oct 10:27 next collapse

@scott Also note that a context doesn't have to be a Collection. You can group by anything. You could set `context` to a Person or Note or Event or whatever you want, if it helped you understand the current object, and if you grouped all objects that shared the same `context` (in a task list, for example). So it's like a tag, but with purpose. If there isn't a purpose, consider using a basic tag.

For "post" objects, it generally makes sense to use a Collection representing the "conversation".

scott@authorship.studio on 20 Oct 12:25 collapse

@infinite love ⴳ So, what happens if a post is part of a thread and a project? How do you know which context is the thread?

My point is that a post can have more than one context.

trwnh@mastodon.social on 20 Oct 12:31 collapse

@scott Right, so, if you have a specific meaning of "thread" in mind, then you can define a property for that. Would you say that a post can be part of more than one thread, or are you assuming a functional (max 1) relationship?

scott@authorship.studio on 20 Oct 13:08 collapse

@infinite love ⴳ Traditionally, a post can only reside in one thread. If you try to assign a post to more than one thread, it breaks a lot of things, like the access list (audience) for the thread, the "owner" of the thread, moderation by administrators, etc.  

That is probably why many people, including myself, want to define a thread as something separate from a collection.

So, I would say that a post can only reside in one thread, but can reside in multiple collections and/or contexts.

trwnh@mastodon.social on 20 Oct 15:21 collapse

@scott Even if you define a thread property, that alone doesn’t stop someone from being able to declare multiple threads. I’m not convinced anyone can define “thread” in a way that is unique or even distinct from what we already have. Access lists are per-object, regardless of whether that object is a post or a collection of posts. You may be able to see a thread, but not all posts in that thread. Conversely, you may be able to see a post, but not the thread(s) it’s a part of.

trwnh@mastodon.social on 20 Oct 15:33 collapse

@scott In any case, being part of a collection isn’t the same as having some context. Being part of a thread *usually* maps onto the concept of having additional context, where the thread provides context for the post, and the post exists in context of that thread. The way you handle context is by using it to group things. That context MAY have an owner, and it MAY be a collection. IF it has an owner, it is common courtesy to send your object to them. IF it is a collection, they may Add it.

trwnh@mastodon.social on 20 Oct 15:40 collapse

@scott You may separately enforce at a protocol level that a post may only have one thread or one context, just as we may implicitly enforce that posts only have one inReplyTo. But the data model has no such restrictions. It is possible to not only *express* multiple values, but we can also expand the protocol to *handle* multiple values, if we wanted to. Loop over ‘context’ and IF resolved to a collection, expose that collection as a “thread”. Maybe require a special type for it if you want.

trwnh@mastodon.social on 20 Oct 15:42 collapse

@scott In UI, this would be shown to the user as: “This post is part of the following context(s):” and then list them. Kind of like a “view full thread” button on a single post’s permalink page.

trwnh@mastodon.social on 20 Oct 16:00 collapse

@scott Just keep in mind that being part of a collection isn’t the same as nor is it sufficient to be declared as a context. Generally avoid declaring unnecessary contexts — if it doesn’t help you in understanding the object by indicating a purposeful grouping, then leave it out or use a different property.

scott@authorship.studio on 20 Oct 18:20 next collapse

@infinite love ⴳ Why does this have to be so complicated?

A thread has always been one thread per post since the beginning of emails, discussion groups, and forums. Even Facebook-style posts are threaded with a post only belonging to one thread.

We are trying to integrate forums into the fediverse.

You can flag posts as being part of contexts and collections as much as you want, but a thread is and always will be a maximum of one thread per post. If that is not the case, it is no longer a thread, and it is a collection or context instead.

Here's the thing. Mastodon and other Twitter-inspired derivatives that do not support threaded conversations will ignore whatever we put anyway, so why should we (forums and platforms that support threaded conversations) comply with how Mastodon and non-threaded platforms do things?

A thread is fundamentally different than a collection or context, and it has been that way since the internet started. If you want a different use case, then don't call it a thread. But let the platforms that have threads call it a thread if they want.

trwnh@mastodon.social on 21 Oct 00:15 collapse

@scott It’s complicated because reality is complicated. If you want to enforce “one thread per post”, you have some options:

- Define in your protocol that only one context may be set, that it should/must have certain properties like attributedTo (the owner) and items (whatever the owner officially blessed to be in the thread). Maybe you also require a type of Thread or Conversation, whatever.

- Clearly define the semantic relationship between a “post” and a “thread” in a unique+specific way

scott@authorship.studio on 21 Oct 00:49 collapse

@infinite love ⴳ Let's look at the practical aspects.

Most platforms that have threaded conversations have two different views: one for threads, and one for collections or lists.

For a blog it is usually presented as the blog post with comment (a thread) vs. a list of posts in a category or as search results (a collection).

For a forum, it is similar, with a top level post and its replies (a thread) vs. a list of posts in a category or as search results (a collection).

For a discussion group, it is the same as the forum, but the UI is different.

For email, you have a threaded conversation (an email and its replies) vs. a list of posts in a category or as search results (a collection).

Notice that they are all similar. Notice that they all have something in common. There are two views, and threads always only have one parent or top level post.

From a very practical developer perspective, I need to choose which view is used to present the posts. Threaded conversations get presented one way, and collections get presented another way.

It would be nice if ActivityPub actually told me whether this is a thread or a collection so I can choose the appropriate user interface.

trwnh@mastodon.social on 21 Oct 01:05 collapse

@scott Those are all just lists, though. If you needed more hinting as to what type of collection you're viewing, then you can declare types like Thread or SearchResults or MediaAlbum or whatever. But hardcoding a check for a specific type is fragile.

The only practical consideration is in knowing whether you can submit an object for inclusion (this is the missing bit, we need a property like "can participate"), and where to send it for consideration (attributedTo).

scott@authorship.studio on 21 Oct 01:11 collapse

@infinite love ⴳ Yes, on the backend they are both lists.

But the UI is VERY different for conversations versus lists.

Since the UI is different for conversations and list, I need to know whether it is a thread or a list of random posts so that I can display it correctly.

scott@authorship.studio on 20 Oct 18:37 next collapse

@infinite love ⴳ You also have to consider that a server may pull the same post for different users, and those posts may have different contexts or collection.

User A is following a project, so when the post is sent to the recipient, the context is marked as being the project.

User B is following a forum, and wants to see all posts related to the thread (conversation). So, depending on how we decide to label forum threads, this may come back a belonging to a thread, belonging to a context, or belonging to a collection.

One thread, multiple posts, but multiple collections or contexts?

Now the app needs to figure out who is the real Slim Shady. Which one is the thread and which one is a collection or context?

It would be a lot easier to manage incoming posts if you explicitly stated which thread the post belonged to.

trwnh@mastodon.social on 21 Oct 00:21 collapse

@scott The “thread” is whatever the object says. The object could say there are multiple “threads”, even if you use a different dedicated property for this.

scott@authorship.studio on 21 Oct 00:40 collapse

@infinite love ⴳ The concept of a thread is probably older than most people in this conversation. It is at least 40 to 50 years old now. I don't think we should change the definition that every email client, forum, and discussion group has used for decades.

Yes, I agree that on the backend, a lot of the stuff is the same but with a different UI. I get it. In fact, I am someone who frequently brings that up.

But there are some very practical considerations on why a thread should be treated differently than a context or collection. And that is mostly because the UI to display a conversation is different than the UI for displaying a collection.

So there needs to be some way to indicate where to retrieve the entire thread.

scott@authorship.studio on 20 Oct 18:56 collapse

@infinite love ⴳ Another thing to consider is that a thread is displayed differently than a collection or context.

A thread is always a parent post and its children (the comments).

Whereas, a collection or context could be a bunch of unrelated posts, and could even be a bunch of unrelated threads.

As such, they are not displayed the same in the UI. Display a collection like a thread would be confusing to users, and displaying a thread like a collection would also be confusing to users.

So a thread should be a thread, and collections and contexts should be something else.

Or if you insist in using collections, then somehow label the collection as being of type thread so the appropriate UI can be served.

trwnh@mastodon.social on 21 Oct 00:02 collapse

@scott

> thread is always a parent post and its children (the comments).

I disagree with this definition, but if this is how you want to define it, then a specific property or type would be best.

> context could be a bunch of unrelated posts, and could even be a bunch of unrelated threads.

If they’re unrelated, then it shouldn’t be a context. Using context is for when your object is *purposefully* related to other objects.

trwnh@mastodon.social on 21 Oct 00:03 collapse

@scott

> Displaying a collection like a thread [or] thread like a collection would be confusing to users.

What’s confusing about putting the “parent post” as the first item in a list, then its “children” in chronological order after it? This is no different than what’s already done.

> somehow label the collection as being of type thread so the appropriate UI can be served.

This intention can be hinted with a dedicated type, yes, but the “appropriate UI” is more flexible than you realize.

scott@authorship.studio on 26 Oct 04:58 next collapse

To give you an example:

Here is a thread (conversation with a topic):

#^https://community.nodebb.org/topic/18364/fep-convergence-400e-7888-171b-conversation-containers-76ea

Here is a collection (a list of posts labelled "Forums and Threaded Discussions Task Force"):

#^https://community.nodebb.org/category/31/forums-and-threaded-discussions-task-force

Notice how they are rendered completely different.

A collection is NOT a thread. And some apps need to know which is the thread so we can render the display properly.

julian@community.nodebb.org on 28 Oct 13:48 collapse

@scott@authorship.studio Yes. Per 1b12, audience is the appropriate property to use to denote a collection of loosely-related objects. context is ideal for closely-related objects (like ones that share a reply tree, but that doesn't rise to the level of a requirement), like posts in a context (topic/thread).

In your examples, the "thread" is a Collection when resolved and is referred to in objects via context. The "category" is an Actor when resolved, and is referred to in objects via audience.

As for the other conversation, it honestly seems like you and @trwnh@mastodon.social are splitting hairs and really want the same things.

scott@authorship.studio on 28 Oct 14:31 collapse

@julian The sticking point is basically whether I should guess what the thread is, or be told what the thread is.

He wants me to perform a bunch of tests and guess; I want it to be declared.

I am not sure what you are going to do when there are multiple collections associated with a post. Because unless the thread is declared, you won't know which is which.

julian@community.nodebb.org on 28 Oct 14:42 collapse

@scott@authorship.studio said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

I am not sure what you are going to do when there are multiple collections associated with a post.

My plan is to take the first item in context and treat that as the most narrowly scoped collection containing that object. The assumption is that the contexts are ordered from narrow-to-wide. Whether or not additional contexts would be helpful is irrelevant to me, as I am converting this object into a NodeBB topic only.

You can make arguments that this is not correct. I will not disagree. I will simply say that, like it or not, this is the simplest form of compliance most implementors will opt for.

scott@authorship.studio on 28 Oct 15:41 next collapse

@julian If that is how you want to do it, I respect that. But I do find it odd that the FEP actually has a field for thread and nobody plans on using it. But, most platforms either have 1 context or 0 contexts, so it makes sense.

I still haven't decided how I will do things with my fediverse-enabled project management system. At some point, there will probably be multiple contexts. If that is the case, I probably will put the thread as the first context and then also declare what the thread is using FEP 76ea or something similar.

That way, at least with my project, you won't have to guess which one is the thread. And since your platform only has one context, then I won't have to guess either.

scott@authorship.studio on 28 Oct 15:56 collapse

@julian The sad thing about this is that we have an opportunity to set the standard here, and we are not taking that opportunity.

Yes, we have to assume that not all platforms will add the additional fields, and we have to have a fallback way of processing incoming posts.

I am just flabbergasted that "thread": "https://remote.example/thread/117", is too hard to include with posts distributed by the forum. Even if you don't use it, some of us might find that to be useful information.

But it appears that I am alone in this, so I will just let it be.

julian@community.nodebb.org on 29 Oct 13:41 next collapse

Hi @scott@authorship.studio, thanks for your thoughts. I took the evening to think it over.

I agree that using thr:thread would be the most explicit way of signalling that NodeBB topics are threads, and if 76ea were to be adopted by a majority of implementors, then I would reconsider. Currently I am on the fence about whether or not I should implement it.

I do want to point out that @trwnh@mastodon.social's FEP 7888 doesn't expressly forbid multiple contexts, and I think upthread they even said that such a use case would not be contrary to the FEP:

based on this conversation i probably need to add examples to fep-7888 of how one might process multiple contexts.
~ trwnh

My opinion today is that when NodeBB uses context, it is doing so to signal that "hey, these posts are part of this collection", and exactly nothing more. It is up to the receiving end to decide how to implement it, and I think that this sort of variety is absolutely wonderful.

If, for example, someone were to see my context and say "I'd like to map this context's objects out into a word cloud and do sentiment analysis on it", I think that's a perfectly cromulent use of the data. For me to say "this here is a thread, and you better treat it as a thread" is contrary to the spirit of ActivityPub and fedidevs in general.

It would be like the ForumWG saying to Eugen, @renchap@oisaur.com, et al. that "we've decided that YOU, Mastodon, need to support as:Listen and render inline players, and playlist support, etc.". That's ridiculous, wouldn't you agree?

trwnh@mastodon.social on 29 Oct 13:55 next collapse

@julian @scott quick notes:

- (they/them btw)
- multiple contexts probably will end up like multiple inReplyTo; idk if most impls will support it. but "which one is the thread" as a question makes no sense bc most likely they are all "threads" in some way
- 76ea thr:thread is a reply tree, not a conversation
- reason i say "context likely == thread" is bc it's **more than just a collection**. it is WHY the object exists. what is a thread if not purposeful grouping?

trwnh@mastodon.social on 29 Oct 14:02 collapse

@julian @scott in other words: for social media / network / "post" purposes, the context is almost always some thread. if it doesn't fit the shape of a thread, then don't treat it as a thread, but in most cases it will. otherwise it wouldn't be a "context", it'd just be some object/collection.

i'm defining "thread" as "when you reify a conversational context, specifically as a collection with an owner and canonical representation, instead of something you have to reconstruct for yourself".

trwnh@mastodon.social on 29 Oct 14:09 collapse

@julian @scott the problem with saying that a "thread" is different from a "conversational context reified as a collection" is that there is no criteria i am seeing by which a thread is different. the thread is a purposeful grouping (context), it has a canonical representation (collection items), and it is maintained by its owner (attributedTo). what more do you need? an explicit declaration that it is a 171b:ConversationContainer? what does that get you?

trwnh@mastodon.social on 29 Oct 14:13 collapse

@julian @scott at best, a dedicated type like ConversationContainer can hint that it was produced by some producer following the ConversationContainer spec/fep/whatever, but the problem is that a) anyone can claim that type without following the spec, and b) it's not actually needed for processing the context property, because you already know it is semantically the context -- the origin or purpose of that object. if it's an id, you group by that id, and if it's a collection then you fetch items

trwnh@mastodon.social on 29 Oct 14:19 collapse

@julian @scott basically if 171b wants to define a ConversationContainer type to signal that a producer is following that fep/spec/whatever then they can do that. i maintain that the use of `target` is still incorrect, invalid, and redundant, but it is what it is. if a similar/different fep defines some other type to signal basically the same thing except in details, then that can also be done. in the end, i would advise that the actual "protocol" doesn't require hardcoded type checking.

trwnh@mastodon.social on 29 Oct 14:28 collapse

@julian @scott in any case the algorithm for processing the post as a topic owner is:

1) loop over `context` for any ids you own
2) if the post is acceptable to you, add it to the relevant collection

the algorithm for processing the post as a third-party observer is:

1) look at `context` to see if any of them are collections
2) pick a collection and navigate to it, discarding the post. if it's actually in the collection, you'll see it again.

trwnh@mastodon.social on 29 Oct 14:35 collapse

@julian @scott that's basically what this all boils down to, really -- not a technical change, but a social one.

our softwares should stop trying to reconstruct shadow collections based on what they *think* should be in there, and they should just browse to the actual collections.

in general, more things should work like web browsers instead of blackboxes that gobble up data and mash it together based on their best guess of how they think it's connected.

scott@authorship.studio on 29 Oct 15:47 collapse

@infinite love ⴳ

our softwares should stop trying to reconstruct shadow collections based on what they *think* should be in there, and they should just browse to the actual collections.

That is my point. If you tell me what the thread is, I can download all of the posts within that thread. I don't even have to parse the reply tree at all.
julian@community.nodebb.org on 29 Oct 16:12 collapse

@scott@authorship.studio @trwnh@mastodon.social I'm at a loss as to why you seem to think this is not possible if the property is called context instead of thread.

scott@authorship.studio on 29 Oct 16:22 next collapse

@julian @infinite love ⴳ As I said before, with platforms like yours, which only have one context, I can assume that one context is the thread.

Declaring which one is the thread is only necessary if you have multiple contexts.

But, I am thinking of other use cases where the context might not be a thread, or there are multiple contexts. In that case, additional clues would be very useful.

The reason why I think we should declare threads as threads is for two reasons:

1. It anticipates future use cases that are different from our own.

2. People tend to copy other people's implementations, and we have an opportunity to set the standard and be the example for others to follow.

So, no, you don't need to declare it a thread in your current implementation. But you may have to make changes later when projects start implementing multiple contexts and they don't conform to your assumptions about contexts.

It is always better to explicitly state something than to force people to guess.

julian@community.nodebb.org on 29 Oct 19:05 collapse

@scott@authorship.studio said in FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea):

It is always better to explicitly state something than to force people to guess.

Partially agreed, but in this case I'd feel better about encouraging implementors to move toward a generic representation of object collections, with the potential for a more straightforward way of defining thread-like actions.

Let's take @trwnh@mastodon.social's example of thread forking. You can already express this using existing activities: as:Remove the forked posts out of the as:context, as:Add them to a new as:context. Maybe sprinkle in an as:Announce or something (I read that somewhere...)

Or perhaps a locked thread: as:context owner sends as:Reject and does not federate out an as:Add to followers.

We could definitely go down the road of designing a bespoke property with associated actions, but I feel like the ActivityStreams vocaulary is fairly expressive, if vague at times... that movement against vagueness is exactly what FEP 7888 is all about.


We don't know future use cases, and there may be cases in which these decisions look wrong in hindsight, but I'd wager that being too explicit is premature, and an approach that is generic enough to express more is better.

julian@community.nodebb.org on 29 Oct 19:16 collapse

@scott@authorship.studio How to handle multiple contexts is indeed a topic that is well worth visiting. I hear you when you say that given multiple contexts, you don't know which one is the thread. I don't have the answers today, but I want to set the framework so that when we do find the answer, we won't be hamstrung by a past decision.

Right now my thinking is that if you have multiple contexts:

  1. You might not need to use multiple contexts (as:context for the thread, as:audience for the collection one level higher)
  2. We should recommend that contexts be ordered from narrowest scope to widest

That ought to handle practically all situations (ready to take my words back on this one hah!)

The one sticking point would be situations where an object is part of multiple contexts at the same scope, e.g. a software that lets you inReplyTo multiple context-independent objects. In that case, not even @evan@cosocial.ca's thr:thread property would help because we'd want to set two threads there too! Now we're back at square one.

So at least for today, we can probably safely declare that if multiple contexts are defined, and they both/all point to resolvable collections, you could treat them all like thread-like data structures, if that's your software's thing.

scott@authorship.studio on 30 Oct 01:05 collapse

@julian I see what you are saying, but you can't assume that collections are thread-like data structures.

In fact, one of the use cases I am looking at is creating a collections of threads, and each of those threads would have comments.

So you would have something like this:

- Project Collection
- - Thread
- - - Top Level Post in Thread
- - - Comment
- - - Comment
- - - Comment
- - Thread
- - - Top Level Post in Thread
- - - Comment
- - - Comment

If you displayed my collection of threads as a thread, it would look like a jumble of unrelated posts because it would be a jumble of unrelated posts. Each thread in the collection would need to be displayed as its own thread, not one giant thread with all posts in it.

To parse something like this, I think I would need to specify which collection is the thread, even if other platforms do not use that field.

Maybe there is another way to do it without parsing the reply tree, but I am not sure. After all, I want the moderated version of the thread, not the reply tree.

silverpill@mitra.social on 29 Oct 18:07 collapse

@julian @trwnh @evan @jenniferplusplus @mikedev @scott @erincandescent @trwnh What if we use context for activities and thread for posts?

erincandescent@akko.erincandescent.net on 29 Oct 18:20 collapse

@silverpill @scott @julian @evan @mikedev @jenniferplusplus @trwnh @trwnh the context property is in the objects, not the activities

trwnh@mastodon.social on 30 Oct 01:21 next collapse

@erincandescent @scott @julian @evan @mikedev @jenniferplusplus @silverpill @trwnh@socialhub.activitypub.rocks it could be either and/or both. it’s really up to you what you declare, and what the collection owner decides to Add. i think there’s a missing piece for signaling the expected shape of what might get added — e.g., “object must have content, attributedTo must be in the audience, etc” but ultimately the collection owner reserves the right to add“unrelated” objects.

trwnh@mastodon.social on 30 Oct 01:27 collapse

@erincandescent @scott @julian @evan @mikedev @jenniferplusplus @silverpill @trwnh@socialhub.activitypub.rocks for example, even a conversation/thread ostensibly bound by context, where every object is expected to share the same “context”, might not actually require this! for compatibility reasons, it may be enough to simply reply to a post with context, if that reply has no context. (if it sets a different context, that’s a clear signal it’s meant for a different thread.)

trwnh@mastodon.social on 30 Oct 01:33 collapse

@erincandescent @scott @julian @evan @mikedev @jenniferplusplus @silverpill @trwnh@socialhub.activitypub.rocks

example 1: nodebb sets a context, mastodon is unaware and replies to nodebb. the reply has no context set. nodebb may want to Add this object anyway? this is an implementation decision based on missing information.

example 2: discourse Moves 6 posts into a new context. to keep anyone following old broken links in the loop, they Add the Move to the context.

scott@authorship.studio on 30 Oct 02:04 next collapse

@infinite love ⴳ True. With incoming posts, you will need to decide how to handle missing information, and decide if it goes into a certain context or thread.

After processing incoming activities and posts, the collection is amended, as appropriate. And internally, you may mark these as part of the context or thread in your own database to make it easier to query.

But one thing is unique about forums: It redistributes the posts to its members. So all outgoing posts sent by the forum could have the appropriate context(s) attached to it.

Since the collection has already been constructed and amended after processing new activities, that collection now becomes the de facto representation of what is in the context or thread according to the collection owner.

So, you have a choice. You can process each post individually and build your own shadow collection, or you could query the existing collection.

Or put another way, do you want to organize the conversation yourself, or do you want to delegate that to the forum or owner of the conversation container.

Option 1 gives you more control over the presentation and organizing of the incoming posts. Option 2 adds an additional layer of moderation that can potentially weed out spam, trolls, and off-topic posts.

There is more than one way to process the same information.

cc: @Evan Prodromou @silverpill @Mike Macgirvin 🖥️ @julian

trwnh@mastodon.social on 30 Oct 02:12 collapse

@scott @mikedev @silverpill @julian

> one thing is unique about forums: It redistributes the posts to its members

this is done via Add or Announce, not by redistributing objects directly, and not by modifying them to inject a `context` property (which is unauthorized)

> you have a choice. You can process each post individually and build your own shadow collection, or you could query the existing collection.

the socially correct thing to do is the latter.

scott@authorship.studio on 30 Oct 03:18 next collapse

@infinite love ⴳ

the socially correct thing to do is the latter.

Is it though? This is the philosophical differences I was referring to earlier.

If someone brought illegal contraband into my home, I have every right to remove both the person and the contraband.

It is similar with forums and conversation containers. If someone posts spam or illegal content, the container owner has every right to remove said content.

As someone who follows a forum, I expect the forum to moderate the content and remove spam and illegal content.

It also becomes a reputation issue. If the forum redistributes spam and illegal content, it can get blocked or shut down.

And nothing about this is forcing you to display the conversation the way the forum does. If you want to process the reply tree, then process the reply tree and create your own shadow collection. That is the freedom of the fediverse. You get to process incoming posts however you want.

But I also have the right to process incoming posts according to my preferences and/or the preferences of the users. You shouldn't infringe on my right to display the moderated version of the thread, just as I shouldn't infringe on your right to display the unmoderated version of the thread.

All of the examples that I gave can be made user configurable. So the end users can decide whether they want the moderated version of the thread or the unmoderated version. So it isn't just about my preferences. It is also about our users preferences.
trwnh@mastodon.social on 30 Oct 03:21 collapse

@scott i'm saying that *because* the conversation owner has the right to remove messages, it is "correct" to *only* check what the conversation contains according to the conversation owner

in other words, we're in agreement that the moderated version should be shown. i don't know why you think or claim i believe the unmoderated version should (ever) be shown...

scott@authorship.studio on 30 Oct 03:24 collapse

@infinite love ⴳ

this is done via Add or Announce, not by redistributing objects directly, and not by modifying them to inject a `context` property (which is unauthorized)

So this is why your forum posts show up as repeats (boosts) in Hubzilla. That is different than how Hubzilla forums work.

Even if you use that set up, the add or announce activity alerts you to the post being part of the collection or context. So even if the method of informing forum members of the post is different, that information can still be used to figure out the context.
scott@authorship.studio on 30 Oct 02:34 collapse

@infinite love ⴳ There are some interesting things you can do with context & thread information.

Display a Collection of Threads

You could display it blog, list, or grid style, with it only showing the top level post, and showing how many comments there are. To see the comments, it will either expand or take you to a new page when you click or tap on it.

You would need to know which collection is the thread to do something like this.

Drop or Collapse Moderated Posts / Comments

If you are following the forum, when the forum redistributes the posts, it tells you the context, and sends activities related to posts within their context (collection). And, ideally, you can backfill the conversation by querying the collection associated with that context.

You can take advantage of the forum's moderation by suppressing or collapsing posts that do not appear in the forum's collection. For example, some platforms will collapse a comment if it has too many downvotes. We could display a comment a similar way if it is not part of the moderated version of the thread (the collection). Users can still read it since it is part of the reply tree, but it is collapsed since it was moderated out of the thread. You can also be more aggressive and drop replies that are not part of the moderated thread.

You can also make exceptions. For example, if a user is following both the forum and an individual user, their posts would appear in your rendering of the thread uncollapsed, even if their post was removed from the collection by the forum.

And this is just two presentations I am thinking of off the the top of my head. There are more ways to display collections.

So, yes, you would still need to process incoming posts, but if information about the thread is provided, additional ways of displaying the information become possible.

cc: @Evan Prodromou @silverpill @Mike Macgirvin 🖥️ @julian

silverpill@mitra.social on 05 Nov 23:07 collapse

@erincandescent @trwnh @evan @jenniferplusplus @mikedev @scott @julian @trwnh
The name of the property could be different, but I think it is useful to have two collections:

- "Thread" is easier to implement, and in any case, software needs to keep track of reply trees, one way or another.
- "Context" is a bonus. It contains everything related to a conversation, including reactions and edits. Some applications may not need it, and for some it might be difficult to implement, so it should be optional.

My estimation is that implementation of "Context" + "Thread" will require roughly the same amount of effort as implementation of "Context" alone, so for those who want "Context" this separation should not be a problem. If software doesn't keep track of activities it can provide empty "Context", but their Add activities should nevertheless have it in target. Perhaps in the following form:

"target": {
  "type": "Context",
  "id": "<context-collection>",
  "attributedTo": "<conversation-owner>",
  "thread": "<thread-collection>"
}
scott@authorship.studio on 29 Oct 15:38 collapse

@julian

If, for example, someone were to see my context and say "I'd like to map this context's objects out into a word cloud and do sentiment analysis on it", I think that's a perfectly cromulent use of the data. For me to say "this here is a thread, and you better treat it as a thread" is contrary to the spirit of ActivityPub and fedidevs in general.

Simply declaring a collection to be a thread does not force people to display it as a thread. But it does provide valuable information to people who do want to display it as a thread.

So you are not removing people's choice by simply stating that on your platform, this is considered a thread.
nice-nigger@nicecrew.digital on 29 Oct 18:10 collapse

REPARASHINS NIGGA :technijew:

scott@authorship.studio on 28 Oct 08:38 next collapse

Reposting here, since the conversation got sidetracked onto Mastodon.

@infinite love ⴳ

Most contexts are multi-faceted in this way. #^https://w3id.org/fep/7888#the-different-types-of-context-and-how-they-are-actually-the-same

Yes they are. But, as I said, there are practical reasons for wanting to retrieve the conversation container (forum thread, social media thread, chat thread, etc.) as opposed to the reply tree.

The biggest practical reason is delegation of moderation. In order to limit spam, trolls, and off-topic discussions, the owner(s) of the conversation container (thread) will moderate content by removing it from the conversation container, moving it to another conversation container, or flagging it in some way.

If @julian spots a spam post on NodeBB, he can delete it. And if I retrieve the conversation container (thread) that NodeBB places the posts in, I will get the moderated version of the thread without the spam. If I parse the reply tree, I get the spam even though Julian deleted it.

It also helps keep conversations together when the forum moderator moves a post to a different thread. If you follow the reply tree, the post would appear in the wrong thread.

If you want threaded discussions to behave like threaded discussions over ActivityPub, you need to provide additional information that allows that to happen.

cc: @Evan Prodromou
scott@authorship.studio on 31 Oct 00:06 collapse

Something like this:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "thr": "https://purl.archive.org/socialweb/thread#",
  "thread": {
    "@id": "thr:thread",
    "@type": "@id"
  },
  "root": {
    "@id": "thr:root",
    "@type": "@id"
  }
  "traits": {
    "traits": "inbox, outbox, conversation, amendable"
  }
}

This would let me know that it is a thread and that people can follow the context. I can then render it as a thread and potentially add a follow or subscribe button for the context.

You could also declare that it does not have an inbox and outbox, which saves me the trouble of checking myself.