FEP-8485: Unbound Actor

MR: #2 - WIP: Add FEP-8485. - fep - Codeberg.org
SoTA: GNUsocial/fep: Fediverse Enhancement Proposals - feps/fep-8485.md at fep-8485 - fep - Codeberg.org

Hello everyone!

It is time to have groups over ActivityPub in #software:gnu-social (instead of OStatus-only).

Groups in GNU social were never perfect. After the death of popular servers such as Qvitter, one could neither target groups hosted at Qvitter anymore nor contact the whole subscribers’ list to let them know of the new server hosting the group.

Groups are always associated with an instance serving as authority over it. Having groups like the ones we already have federating via ActivityPub is easy. But we were thinking: “What if the groups that GNU social currently has federating via OStatus are in fact what in ActivityPub would be better named of “Organization”?”.

We want to offer groups virtually dissociated from instances to end-users. I.e., remove the @instance of !group@instance, and instead have !org@instance used for organisations.

We have been thinking about it for some time now and finally drafted this proposal.

If this is insane, we can instead implement the logic of our OStatus groups in ActivityPub and forget about this path. If, on the other hand, this is sane and safely implementable in the proposed or a different manner, please let me know :slight_smile:

Kind regards,
Diogo

1 Like

I would love to see support for Groups that are not tied to a particular instance as they are now.

But I feel that using “Organization” for that under the covers would be an abuse of the semantic meaning of this concept.

One thing I think would be of great benefit to the Fediverse and have posted a lot about in various threads (like in this post and one’s following) is to truly define the concept of “Community” so that we can finally decouple from the technical terminology of seeing an ‘Instance’ server boundary as being an implicit community. I.e. have a better Community abstraction than we have now.

Ideally then each fedi instance then has an endpoint where you can query about its capabilities (I think de-facto a Service actor is used for that, not sure?), but the accounts / member base can be found on one or more “Community” actors (technically a Group with some AP extensions to it) that the server exposes. And having these communities be entirely server / instance independent (should one want that), would be fantastic.

1 Like

Thanks for your helpful inputs. I’m unsure if I got all of it so, I’ll try to comment a bit on every item so you can correct me if I misunderstood you.

The actor type we are suggesting to use for “umbrella groups”/“decentralised group” is Group. Which is why we suggest using Organization as an actor with moderation/administration beyond local. Organizations could be used for orgs, a musical band or anything that must have a presence in the fediverse with administration. This can still be an abuse of semantic, but we don’t think it is…

The connections attribute in our proposed actor Group would better be a relationships attribute. Where then the collection entries could be Relationship objects such as:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "!lug@social.undefinedhackers.net is linked with !lug@gnusocial.net",
  "type": "Relationship",
  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug"
  },
  "relationship": "http://purl.org/vocab/relationship/collaboratesWith",
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug"
  }
}

For GNU social v3 (the upcoming major release), we haven’t been trying or aiming at giving an impression of a single network via the fediverse. Instead, we interpret each server as a different “nation”, and give more filtering and sorting abilities to the end user. That is, without a moderator or administrator in a group, we simply let the user mute whoever actor he doesn’t want to subscribe to. I.e., there’s no imposed administration/moderation, it’s up to the user to manually filter his feed.

The exception would be with regards to Organisations, where there is a legit reason to have administration and subject all the participants to the same moderation. We want to let any other form of hierarchy for Persons being locally managed rather than federated, the sysadmin can preset feeds, and persons can share feeds. And every feed already includes the muted actors and other selection queries.

This is all to say, in terms of ActivityPub, this proposal aims at linking the greatest number of Groups possible without additional network requests being done. But locally a Person would still be able to artificially unlink a specific Group actor from spamming his feed.

Maybe use Nodeinfo for the query? Note that with this proposal it stops being very relevant to have a members list for groups, each server only cares about knowing two things:

  • Which local users should be notified of what entered !lug inbox?
  • Which !lug@remote should be notified of what my local user just posted to !lug inbox?

Just going to give a bunch of feedback and hopefully something of value to ya :hugs:

Yes, I agree. I think that I was thinking too narrowly on the concept. In definitions of “Organization” (e.g. Free Dictionary) there’s things like “the state or manner of being organized” which is as broad and generic as can be.

In my (probably naive, as I’m no expert) diagram, see embedded in this post , I went from the Group as having the relationships to define the social fabric of its Community organization (mostly to limit impact and scope of the extension). In another thread on a Community AP extension, particularly this post by @lynnfoster shows that Valueflows (which has been implemented in a #software:bonfire module), defines the relationships at the Actor level. And that may be a more appropriate design after all, giving largest amount of flexibility.

Then, when just talking about Group… there’s 2 parallel discussions ongoing about the same topic of standardizing their design, and formalizing that in (one or more) Fediverse Enhancement Proposals, or #standards:fep. These are:

When I talk about “Community” and “Community has no Boundary” as a paradigm, I am solely interested in being able to express richer associations in the social graph than we do today (the relationships aspect). In this it is the ‘space between’ otherwise fragmented and dispersed Groups that is of most interest. The ability to tie those together in meaningful ways and thus “weave a Social Fabric”.

(I was also pondering whether relationships might contain Actor objects directly, besides only allow for Relationships. That may ease implementations where groups have just members, no other ‘organization’ to them than that, and seeing an Actor in the collection would then default to a member_of relationship)

Note that Moderation has nothing to do with all this. It is imho a wholly separate concern that is independent of a Community AP extension. In domain-driven design speak, Moderation is in a different ‘bounded context’ than Community. If you combine the two together, one might say you get a “Moderated Community”. A Moderation bounded context could undergo a similar standardization and have one or more FEP’s and/or Vocabularies defined that will guarantee a certain level of interoperability.

I am just mentioning this. Think you are already keeping things separate. We should just avoid that a Group means that by definition it should have this_and_that moderation features and admin_mod_member privileges, or something like that, in order to be interoperable.

(Btw, I wrote a separate topic on Federated Moderation: Towards Delegated Moderation?)

About “Decentralised Group”. I wonder if we can find a better term for it. After all, Groups as they are now (tied to an instance) with Relationships to other groups elsewhere on the fediverse, are already decentralized. Dunno such terms now, other than “Unbound Groups” or something like that. The way to set them free from their instance in this proposal constitutes a workaround for a broader limitation of ActivityPub to be addressed: ID’s tied to the domain via an URL.

Also wanted to point to a related FEP in process, by @grishka namely: FEP-400e: Publicly-appendable ActivityPub collections.

PS. In terms of notation… I don’t know if there’s some ‘standard’ way, but I see formats as Activity{Object} in use which to me makes it clearer that the activity wraps the object, whereas Activity/Object might lead to confusion if people read it as an ‘or’ or ‘and/or’ choice.

2 Likes

Before anything, I want to honestly thank you for the time, dedication and attention you’re putting into this. The discussion threads you’re referring to are long and full of different concepts. And you pointing at various of their aspects while explaining truly helps :slight_smile:

I think I ended involving too many different assumptions and concepts in a single proposal, when what I wanted, and wasn’t fully making that step, was to focus in this one aspect that you have just emphasized.

To fill the gap between otherwise disperse groups and provide an experience equivalent to that of only having one group everywhere that is not bounded to any single server.
And this mode of operation should always be optional. It should be possible to only do that with three groups instead of every group, as well as stop or start doing it when wanted.
While always leaving federated administration and/or moderation be its completely separate and not necessarily related thing.

I had that intention but I was implying that a Group ideally would always maintain a relationships collection with as many collaboratesWith as possible.
And that this wouldn’t be possible for an Organization.

But it’s much better to let any actor hold a relationships collection and this proposal should instead focus on how, and probably while using FEP-400e, can we “unbound” a group or an organisation from a single server, when that is indeed desired.

The http://purl.org/vocab/relationship/collaboratesWith I ended selecting is not ideal, as it can be needed to express other things more accurately. The same is true, for the same reason, towards using http://xmlns.com/foaf/0.1/knows.

Maybe then use https://w3id.org/#AgentRelationship instead and thus have the roles specified in the subjects:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "!lug@social.undefinedhackers.net is linked with !lug@gnusocial.net",
  "type": "Relationship",
  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug",
    "role": "link"
  },
  "relationship": "https://w3id.org/#AgentRelationship",
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug",
    "role": "link"
  }
}

If the relationships collection is going to allow a group to express relationships with other groups (such as part_of), and both let a person follow its feed vs be a member of it, then it may be better to always be
explicit with what relationship is being expressed…

Indeed in the “augumentation mechanism” proposed here, for each new remote group discovered, if they have the gs:unbound attribute set to true, it could:

  • Send a request to be added to their relationships as described in FEP-400e;
  • If authorised, then add the remote !hackers to its own relationships collection.

I think the issue we had with GNU social’s OStatus groups is clear. And, in the Groups implementation discussion, we had vaguely commented about this umbrella method as a possible solution to this issue.

I started a new discussion because I felt that maybe the proposed “Connections augmentation mechanism” was a bit tangent to these discussions. As this is mostly specific to removing the dependency on a single server for a group and not so much about what a Group is and how to interact with it (although both things are necessarily related, as you have just shown).

Anyway, I’m definitely not looking forward to implement an AP extension or convention that only GNU social will understand and, as hopefully is clear, I want to discuss this and end with a good specification (which definitely doesn’t have to be one originally proposed by GS) in hands to implement.

To follow up on this, do you think I should:

  • Move this proposal to one of the ongoing discussions and close this discussion (to avoid duplication);
  • Rename the current discussion to Unbounded Group (to make it more clear and specific);
  • Submit this as a FEP with the corrections you’ve pointed me for further discussion (such as using relationships, and use FEP-400e between groups to update the collections).

Or, if this is not a new concept, or not much different of something already proposed, could you point me to it so we can start implementing it on GNU social? You mentioned that #software:bonfire already has an implementation that uses Vlueflows, is there a spec of how their groups work?

Happy new year! :smiley:

2 Likes

You mentioned that #software:bonfire already has an implementation that uses Vlueflows, is there a spec of how their groups work?

@mayel @ivan would know better about the plans, but afaik Bonfire hasn’t yet implemented Valueflows agent model (although several other parts of VF are implemented). We have talked about it several times, but it isn’t actually simple, because it involves mapping the agent and the actor models, and there’s a bunch of discussion that could happen there, with both short term (less discussion) and longer term (more discussion) possible solutions. (I can say more if you like, but don’t want to hijack this either. :slight_smile: )

2 Likes

We have implemented VF agents but agent relationships are still on the to do list.

Currently in Bonfire we map Person Agents (in the API) to User (in the database) and Organization to SharedUser (which is simply a user identity that multiple accounts can identify as, such as an Organisation or Team where all members are equally admins). Groups and more flexible forms of organisations are on the backlog (both will use our existing implementation of circles and boundaries to manage membership, roles, and permissions, which will then be mapped to VF agent relationships).

For federation, we simply map Person Agents to AS:Person and Organization to AS:Organization.

1 Like

Hi @mayel, thank you for joining this discussion :slight_smile:

What happens when two #software:bonfire servers want to share the same organization?

What happens when two #software:bonfire servers want to share the same organization?

Currently all admin-members of the organisation need to use the same instance.

The question about how to enable cross-instance use of shared actors in a complex one which I brainstormed a while back (during my time working on MoodleNet) regarding groups and shared collections, here are a few of those ideas (which I haven’t revisited since then):

3 Likes

So, I tried to rewrite the original proposal so it is more focused on unbounded groups. Let me hear your thoughts :slight_smile: . In the meantime, recent discussion in GNU social IRC has rewind the idea of automated group move to the one with more local followers when the previous one becomes unreachable for a certain period of time. I still prefer the one presented below as I don’t think it has as many corner cases and shortcomes, but included this concept in the summary and think it is very worthy of raising in discussion.

FEP-b615: Unbounded Actor

Summary

Historically, after the sudden death of a popular instance, one could neither target groups hosted at it anymore nor contact the whole followers collection to let them know of the new instance housing a certain group. If we always have absolute knowledge of the complete followers collection (or good enough), we can automate based on which instance has more local followers which server would become the new house. Another alternative would be to automatically archive the old group and start again from scratch.

This FEP, on the other hand, discusses something very different of automatically moving an actor from one server to a different one. It is about collaboration between different group actors to promote an unified experience between the participants of the linked group actors. We think this may be easier, flexible, and promotes a better UX than only notifying the actor that the house of a certain group has moved, but both solutions would probably achieve similar results in the above use case.

This proposal introduces two concepts: Group Link Relationship, and gs:unbound. The first makes two groups “act as one”, the second triggers a mechanism that attempts to augment that collection of linkedGroups in an opportunistic manner.

This aims at effectively removing a central point of authority for groups, which is a probably useful functionality. With this, @alice@undefinedhackers.net can mention a group named hackers (!hackers) or even address an activity To !hackers@social.undefinedhackers.net (C2S) and let her instance’s !hackers announce to other instances’ !hackers.

Finally, this proposal is general enough to allow a server to simultaneously have !lug@server (without links), !lug-unbounded@server (with the greatest links collection it can grow), and !lug-with-some-links@server (with only some links). It doesn’t require linked groups to have the same preferredUsername.

Notation and Definitions

To keep things simple, sometimes you will see things formatted like Activity{Object}. For example, Create{Note} would be a Create activity containing a Note in the object field.

  • @nickname@server will be used to refer Actors of type Person or Application.
  • !nickname@server will be used to refer Actors of type Group or Organization.
  • @#!group@server#collection will be used to refer collection collection of !group@server.

Other FEP Dependencies

ActivityStreams 2.0 requirements for this mechanism

Example Group Actor in this FEP

{
  "id": "https://social.undefinedhackers.net/group/hackers",
  "type": "Group",
  "gs:unbound": true,
  "preferredUsername": "hackers",
  "linkedGroups": "https://social.undefinedhackers.net/group/hackers/relationships",
  "endpoints": {
    "sharedInbox": "https://social.undefinedhackers.net/inbox.json"
  },
  "inbox": "https://social.undefinedhackers.net/group/hackers/inbox.json",
  "outbox": "https://social.undefinedhackers.net/group/hackers/outbox.json",
  "publicKey": {
    "id": "https://social.undefinedhackers.net/group/hackers#public-key",
    "owner": "https://social.undefinedhackers.net/group/hackers",
    "publicKeyPem": "..."
  }
}

The linkedGroups attribute points to an OrderedCollection of URIs of actors of type Group in other servers that this group has established a “link” agent relationship with.

This attribute MUST be present in the actor if it wants to take advantage of the extension described in this document.

{
  "type": "OrderedCollection",
  "id": "https://social.undefinedhackers.net/group/hackers/relationships/links",
  "orderedItems": [
    "https://gnusocial.net/group/hackers",
    "https://social.diogo.site/group/hackers",
    "https://social.eliseuama.ro/group/hackers",
    "https://social.hsal.es/group/hackers",
    "https://status.hackerposse.com/group/hackers"
  ]
}

The collection is ordered lexicographically, making it faster to compare and merge with other collections.

Example of a Group Link relationship

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://social.undefinedhackers.net/group/lug/relationships/links/1",
  "summary": "!lug@social.undefinedhackers.net is linked with !lug@gnusocial.net",
  "type": "Relationship",
  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug",
    "role": "link"
  },
  "relationship": "https://w3id.org/#AgentRelationship",
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug",
    "role": "link"
  },
  "target": {
    "type": "Collection",
    "id": "https://social.undefinedhackers.net/group/lug/relationships/links",
    "attributedTo": "https://social.undefinedhackers.net/group/lug"
  }
}

Link request using FEP-400e

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "summary": "!lug@social.undefinedhackers.net wants to link with !lug@gnusocial.net",
  "actor": "https://social.undefinedhackers.net/group/hackers",
  "id": "https://social.undefinedhackers.net/activity/1337",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "type": "Create",
  "object": "https://social.undefinedhackers.net/group/lug/relationships/links/1",
  "target": "https://gnusocial.net/group/hackers/relationships"
}

The handling of the above activity happens as described in [FEP-400e], Section “Adding an object of a colection”.

Assuming that !hackers@social.undefinedhackers.net and !lug@gnusocial.net have mutually agreeded in adding each other to their links, that will result in !hackers@social.undefinedhackers.net Announcing{*} entering its inbox to !lug@social.gnusocial.net and vice versa. Allowing them to act as if they were the same group. If they have equivalent groupLinks collections, then they are essentially fully mirrored groups.

Note that the “Linking negotiation” happens between two Group actors (S2S).

Example Announce{Note} from a Group and targeted at another Group (S2S)

{
    "@context": [
        "https://www.w3.org/ns/activitystreams"
    ],
    "id": "https://social.undefinedhackers.net/activity/1337",
    "type": "Announce",
    "actor": "https://social.undefinedhackers.net/group/hackers",
    "published": "2021-12-29T13:37:42Z",
    "to": "https://social.undefinedhackers.net/group/hackers/relationships/links",
    "cc": [
        "https://www.w3.org/ns/activitystreams#Public"
    ],
    "object": {
        "id": "https://social.hackersatporto.com/object/note/31337",
        "type": "Note",
        "published": "2021-12-29T13:37:42Z",
        "attributedTo": "https://social.undefinedhackers.net/person/1",
        "to": [
            "https://www.w3.org/ns/activitystreams#Public"
        ],
        "cc": [
            "https://social.hackersatporto.com/index.php/user/1"
        ],
        "content": "<p>hello, <span class=\"h-card\"><a href=\"https://social.undefinedhackers.net/!hackers\" class=\"u-url mention\">!<span>hackers</span></a></span></p>",
        "tag": [
            {
                "type": "Group",
                "name": "!hackers",
                "href": "https://social.undefinedhackers.net/!hackers"
            }
        ]
    },
    "signature": {
        "type": "RsaSignature2017",
        "creator": "https://social.undefinedhackers.net/group/hackers#public-key",
        "created": "2021-12-29T13:37:42Z",
        "signatureValue": "..."
    }
  }
}

The local persons interested in interacting with an unbounded group MAY mention it using !group without the @server bit, the local server in that situation can assume !group@server. !group@server will then reproduce the above Announce activity.

Opportunistic linkedGroups Augmentation Mechanism (when gs:unbound is true)

Let’s suppose that the Announce above has just been delivered to https://gnusocial.net/inbox.json.

And let’s assume the following items in !hackers@gnusocial.net's linkedGroups collection:

  "orderedItems": [
    "https://loadaverage.org/group/hackers",
    "https://social.diogo.site/group/hackers",
    "https://social.undefinedhackers.net/group/hackers"
  ]

gnusocial.net must include the unknown addressed to actors in its own linkedGroups collection (excluding itself), so that it becomes:

  "orderedItems": [
    "https://loadaverage.org/group/hackers",
    "https://social.diogo.site/group/hackers",
    "https://social.eliseuama.ro/group/hackers",
    "https://social.hsal.es/group/hackers",
    "https://social.undefinedhackers.net/group/hackers",
    "https://status.hackerposse.com/group/hackers"
  ]

For that it should use the described in section [Link request using FEP-400e] for each new group.

Obs.: If in the addressed to groups there’s one that gnusocial.net knows to be dead, the dead actor should be in a temporary list for sufficient time to avoid re-adding it to the connections.

Obs.: This only happened because the actor had the gs:unbound attribute set to true.

Obs.: gnusocial.net should record groups that have previously rejected a Link request.

Examples

Please note that the following examples are not independent, each continuously builds on the previous one.

1. Creating a group with a link

  • !hackers@A: Create{Group}

@#!hackers@A#linkedGroups = []

  • !hackers@B: Create{Group} (S2S)
  • !hackers@B: Create{Relationship} TO !hackers@A (S2S)

!hackers@B#linkedGroups = [A]

  • !hackers@A: Create{Relationship} TO !hackers@B (S2S)

!hackers@A#linkedGroups = [B]

  • @alice@B: Create{Note} TO !hackers@B (C2S)
  • !hackers@B: Announce{Note} TO !hackers@[A] (S2S)

@#!hackers@A#linkedGroups is unchanged as he was the only in TO

2. Opportunistic linkedGroups Augmentation Mechanism

  • !hackers@C: Create{Group}
  • !hackers@C: Create{Relationship} TO !hackers@B

@#!hackers@C#linkedGroups = [B]

  • !hackers@B: Create{Relationship} TO !hackers@C

@#!hackers@B#linkedGroups = [A, C]

  • @bob@C: Create{Note} TO [@tux@D (S2S), !hackers@C (C2S)]

Let’s assume that D either doesn’t have the group !hackers or has the group but @#!hackers@D#linkedGroups = []

  • D fetches !hackers@C and merges the existing linkedGroups (none) with !hackers@C’s linkedGroups

  • !hackers@D: Create{Relationship} TO !hackers@B (S2S)

@#!hackers@D#linkedGroups = [B]

  • !hackers@B: Create{Relationship} TO !hackers@D (S2S)

@#!hackers@B#linkedGroups = [A, C, D]

3. Forwarding from Inbox

  • !hackers@C: Announce{Note} TO !hackers@[B] (S2S)
  • B will be kind enough to inboxForward this activity TO A
  • A fetches !hackers@C and merges the existing linkedGroups with !hackers@C’s linkedGroups
  • !hackers@A: Create{Relationship} TO !hackers@C (S2S)

@#!hackers@A#linkedGroups = [B, C], was updated due to the proposed augumentation mechanism

  • !hackers@C: Create{Relationship} TO !hackers@A (S2S)

@#!hackers@C#linkedGroups = [A, B]

This is not the same as the defined in [ActivityPub], Section 7.1.2. As it does not respect bullet points 2 and 3. It instead acts on the premise that there are values in to that the sender doesn’t yet know about but would like to, this is a safe premise when the gs:unbound attribute is set to true.

N.B.: Unless the linkedGroups in the To are exactly the same as the ones the receiving instance already has, a diff will always have to be made. Therefore, noticing that some of ours linkedGroups aren’t going to be notified is a free by-product of augumenting our current linkedGroups.

4 Likes

@diogo wow! It will take me a while to get deep enough into where you are going to be maybe helpful. In the meantime, a couple thoughts. And apologies if I don’t get it yet.

I think the concept of “unbounded actor” is super interesting. You probably don’t want to go there, but the way I’ve thought about it is to also include Person, Group, Organization in other technology ecosystems, besides different installations within the fediverse. But even just considering the fediverse, you are hitting on one reason mapping agent and actor is complex. Conceptually, one actual agent can be represented by many actors, and your Group !hackers is a perfect example. Let’s say theoretically that “one agent” is a foaf:agent. And in addition to social activity, that agent engages in economic activity with other agents. So, it becomes more important that the agent is identified more generally than an actor on one fediverse installation supporting social activity. Even besides the issue of servers going away. At least I think; I could be wrong. But I’m also thinking about your more flat P2P kind of structure, which I need to go through in more detail to make sure I understand how flat it is.

Re. using vf:AgentRelationship for your link relationships, snippet from your comment:

  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug",
    "role": "link"
  },
  "relationship": "https://w3id.org/#AgentRelationship",
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug",
    "role": "link"
  },

vf:AgentRelationship works a lot like as:Relationship. The vf:AgentRelationship includes the subject, relationship, object, just like as:Relationship. Like one as:Relationship could be “http://purl.org/vocab/relationship/link” if that existed.

So using the vf role, I think it would look more like this, unless I’m missing something, which is possible!

  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug"
  },
  "relationship":{
    "type": "vf:AgentRelationshipRole",
    "id": "https://example.org/role/link"
  },
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug"
  },

Thinking about it, maybe using as:Relationship would be cleaner for you, since it avoids the issue of is agent:actor 1:M or 1:1 ? Except it goes just one direction, if I understand correctly? But that’s solvable.

  "subject": {
    "type": "Group",
    "id": "https://social.undefinedhackers.net/group/lug"
  },
  "relationship":"https://example.org/relationship/link",
  "object": {
    "type": "Group",
    "id": "https://gnusocial.net/group/lug"
  },

(I’m thinking you can’t really put the role inside the subject and object, which are actors.)

2 Likes

Here’s some thoughts, just brainstorming, on this latest version…

Update: I didn’t post this yesterday as I was uncertain on my AP/LD/VF knowledge and asked on fedi, and am delighted to see @lynnfoster’s update, as I was thinking in a similar direction with the relationship property having the range of as:Object. And also defining relationships at Actor level. Adjusting my text to Lynn’s suggestion…


Unbound Groups

Definition (I’d use singular instead of plural):

Unbound Actor: An ActivityStreams Actor that is independent of the instance(s) that host it.

With that name I think the scope of this FEP should relate to any actor-type, not just Group. That also makes it more compatible to Valueflows, which defines relationships between ‘Agents’ on the same level.

The challenge to overcome is that the ActivityPub Object ID ties any object to a domain via an URL, and hence ties to an instance. The Unbound Actor FEP provides a workaround until the time that a better ID mechanism (content addressing, DID’s, … ?) is specified.

In this Group Link Relationship is a specialization of Actor Relationships, and gs:unbound an indicator of the Unbound Actor workaround being used. So I wonder if all this couldn’t be generalised to define these actor relationships.

Valueflows

Valueflows writes the following on Agent Relationships (see also: example):

click to expand Valueflows Agent Relationships documentation and ontology diagram ...

Agent relationships have many nuances, thus VF provides the ability to define one’s own kinds of relationships. For example people might “participate” with an organization by means of agreeing to terms and conditions. Or people might have more active “membership” in a group or organization. Or people might consider themselves members but want a more independently flavored term such as “affiliates”.

A relationship can be direct, like “steward”, or more like a role, for example “grower” or “harvester” for a food network.

Relationships can also include roles like “sub-organization” or “trading partner”.

There are a number of useful Properties in existing vocabularies that can be used. Or people can create their own as needed.

Relationships have direction: For example, in “Michael is a member of Enspiral”, Michael is the subject and Enspiral is the object. In this case the inverse is also valid, “Enspiral has member Michael”. In VF, we consider this to be one relationship. One directional relationships like “follows” are also supported.

Relationships can be in a scope (or not): For example, “Kathy is mentor of Sam, in the scope of Enspiral.”

@lynnfoster here on SocialHub provided the following diagram of the ontology that Valueflows uses for that:

Valueflows Agent Relationships ontology

  • An actor can have zero or more relationships
  • Some relationship types are commonly understood (standardized)
  • Other relationship types can be custom defined (app-specific)

One thing I wonder about in the Valueflows specification of AgentRelationship… it looks like, by using roleLabel and inverseRoleLabel in AgentRelationshipRole, you lose the ability to define standardized Linked Data relationships. The only supported relationship is a Valueflows relationship. If you consider for instance the FOAF, Relationship, GoodRelations or Schema.org or many other ontologies, you want to standardize from widely adopted semantics defined there.

Actor Relationships

Though it is a bit vaguely defined in ActivityPub the streams property can contain “A list of supplementary Collections which may be of interest.”. And in @mayel’s doc for #software:bonfire this is also used. Then the Group may be:

{
  "id": "https://social.undefinedhackers.net/group/hackers",
  "type": "Group",
  "preferredUsername": "hackers",
  "streams": {
    "relationships": "https://social.undefinedhackers.net/group/hackers/relationships"
  },
  "endpoints": {
    "sharedInbox": "https://social.undefinedhackers.net/inbox.json"
  },
  "inbox": "https://social.undefinedhackers.net/group/hackers/inbox.json",
  "outbox": "https://social.undefinedhackers.net/group/hackers/outbox.json",
  "publicKey": {
    "id": "https://social.undefinedhackers.net/group/hackers#public-key",
    "owner": "https://social.undefinedhackers.net/group/hackers",
    "publicKeyPem": "..."
  }
}

(Note: If I look at the ActivityStreams definition of Relationship, then isn’t Example 47 invalid? The value of relationship property cannot be "http://purl.org/vocab/relationship/acquaintanceOf" as the range is as:Object. But that may be my limited LD understanding shining through.)

Here I follow up from @lynnfoster. But relationship should be an as:Object first. Idk, but maybe to express the relationship type the url property can be used. And maybe to express RoleBehavior (grouping of relationships into categories) the context property may be used. The spec says about “context”:

The notion of “context” used is intentionally vague. The intended function is to serve as a means of grouping objects and activities that share a common originating context or purpose. An example could be all activities relating to a common project or event.

With that, when dereferencing the relationships collection, something like this is returned:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "https://social.undefinedhackers.net/group/hackers/relationships",
  "type": "Collection",
  "items": [
    {
      "id": "https://social.undefinedhackers.net/group/hackers/relationships/1",
      "summary": "!lhackers@social.undefinedhackers.net and !lug@gnusocial.net are the same",
      "type": "Relationship",
      "subject": {
        "type": "Group",
        "id": "https://social.undefinedhackers.net/group/hackers"
      },
      "relationship": {
        "type": ["Object", "vf:AgentRelationshipRole"],
        "id": "https://social.undefinedhackers.net/groups/role/sameAs",
        "url": "https://schema.org/sameAs",
        "context": "https://social.undefinedhackers.net/nodeinfo/capability/UnboundGroups"
      },
      "object": {
        "type": "Group",
        "id": "https://gnusocial.net/group/lug"
      }
    }
  ]
}

In other words the Unbound Group that is hosted across 2 instances is indicated with a “sameAs” relationship, and the “context” makes clear how we should interpret the relationship’s meaning (UnboundGroup capability).

I left out the target here, because I’d need to learn more about this before doing so. In ActivityStreams 5.2.1 Modeling friends requests is an interesting flow to look at, I think.

This way an arbitrary number of different relationships could be defined between actors. The “context” as RoleBehavior might serve as a filter to only retrieve the ones that are interesting.

In the regular Groups implementations we have right now the “member_of” relationship is expressed via the followers collection I think. This may continue to be so, but only for a single relationship type i.e. “follows”. The Follow activity is defined in ActivityStreams as:

Indicates that the actor is “following” the object . Following is defined in the sense typically used within Social systems in which the actor is interested in any activity performed by or on the object. The target and origin typically have no defined meaning.

That also indicates a single type of relationship (though to me it seems to be different in meaning than a “member of” relationship. Someone can follow a Group without being a member. But it is as it is).

Standardized relationship types

In the example above there would be a need to standardize a set of relationship types and maybe contexts to be universally understood across the Fediverse. Just brainstorming, but e.g.

context (capability) relationship types
Unbound Groups https://schema.org/sameAs
Organization Structure http://purl.org/vocab/relationship/childOf
http://purl.org/vocab/relationship/parentOf
http://purl.org/vocab/relationship/siblingOf
Offering http://purl.org/goodrelations/v1#offers
http://purl.org/goodrelations/v1#seeks

Etcetera…

Minor remarks

In @mayel’s document there is some terminology that seems to indicate a specialization of Groups, in other words app/implementation-specific. Probably perfectly fine, because it was created in that context, I think. But want to mention anyway…

  • “User creates Group” → “Person creates Group” (I personally try to avoid “user” altogether)
  • “Moderator” → yes, if you have moderators, but the notion of that is app-specific
  • “The context field contains the parent Group’s id/uri” → a parent relationship?

I did not look into SharedCollections. I know too little about the low-level stuff needed still. But may spend more time on this :hugs:

2 Likes

Yes, good point, and I really like the direction you’re going in general.

Although I can’t just speak for VF, I would personally be happy to use a more universal agent model instead of the one we have, which is partly foaf, partly org, but all vf in the relationship area because we couldn’t find what we needed, and weren’t thinking outside of the vf economic model at that time. Now that we’ve been working with Bonfire and others, seeing the necessary integration of social and economic, etc., I picture this whole area (people, orgs, groups, relationships) being its own vocabulary, which could be used by other vocabularies, instead of each one having their own version. And maybe just some more flexible range definitions or some cross-vocab owl:sameAs kind of things would do a lot, but I don’t have enough rdf coding experience to know what that means for devs. But is that more in the spirit of the web?

2 Likes

Hi Everyone,

I wanted to add to this discussion because I’m starting work on a project that’s focused on communities, and have been looking at the implementation of distributed communities with ActivityPub. So I’m finding everything in this thread very interesting :slight_smile:

I like to consider a distributed community as being something ephemeral and requiring minimal management or intervention - it should be easy to connect to in the same way that (originally) public Internet exchange points are - you specify where you need to go and you’re connected. And you should be able to connect to wherever and whatever you want to. It shouldn’t be necessary to have to manage peering with other services.

So when I started looking at it this way and in the context of the ActivityPub specification, isn’t this what the context field is for? For example, something like this:

{
  "type": "Note",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "name": "My post to a community",
  "content": "Hi world!",
  "context": [
    "https://yuforia.com/topic/anything",
    {
      "type": "Topic",
      "name": "anything"
    }
  ]
}

Anyway, just throwing my $0.02 in, mostly just want to get involved and figure this out. I’m fairly new to ActivityPub, but not forums and communities.

Yes, I think you’re correct.

Yes, I was trying to generalize to any actor. But then focused on groups throughout the rest of the document because it becomes easier of understanding the aim of the proposal. For Persons I don’t think it makes a lot of sense to have the proposed relationship, I guess it is essentially for either Groups and Organizations. I’m not considering Service as I don’t know much about it yet.

The example link isn’t available :confused:

I was considering this Link relationship as something Directed. I.e., Group A asks whether Group B wants it to Announce everything in its inbox to it, and vice versa.
To try and give an example where this could be useful: Group B could be a closed debating group that receives activities from other groups and debates it internally without polluting the other groups. People could still Follow Group B.

For that reason, I’m not sure https://schema.org/sameAs expresses exactly what we want. Also because, even if Group A and Group B are linked, they still are different actors that can have a different collection of relationships and most definitely a different one of followers.

I like that idea of using the context.
When I suggested using NodeInfo I wasn’t thinking on it like this… Just as a way of querying whether a server supported something or not. I’m not sure if you can use it like this.

For communities, if you haven’t already, it may be helpful to have a look at #software:lemmy’s implementation and the ongoing discussion in standardizing on a common community extension.

With regards to your use of context, I think that would be semantically correct. But I think that what is usually done is to have the topic post being a “root note/page” and the follow ups being replies (inReplyTo). In OStatus there is the conversation URI, which expresses the same that I think you are trying to.

I don’t know enough about rdf to come with something here either, but was searching for alternatives that can potentially model this or at the very least bring new ideas/perspectives. And have found AgRelOn, an Agent Relationship Ontology and the Agreements ontology . They are tangent as their usage domain is fairly different of ours.

I was unable to find a LOV that models this directed collaboration/knowledge relationship/agreement between actors/agents.

@lynnfoster and @aschrijver: I don’t really like AgentRelationshipRole requires an ID… I was playing in JSON-LD Playground and came up with this:

{
	"@context": {
		"@vocab": "https://www.w3.org/ns/activitystreams",
		"vf": "https://w3id.org/valueflows#"
	},
	"summary": "!hackers@social.undefinedhackers.net links to !lug@gnusocial.net",
	"id": "https://social.undefinedhackers.net/group/hackers/relationships/123",
	"type": "Relationship",
	"subject": "https://social.undefinedhackers.net/group/hackers",
	"relationship": "vf:AgentRelationshipRole",
	"object": "https://gnusocial.net/group/lug",
	"context": {
		"vf:roleLabel": "has a link to",
		"vf:inverseRoleLabel": "has a link from"
	}
}

The id of this AgentRelationshipRole would thus expressed by the Relationship Activity’s id… Would this work instead or is it too much of a stretch?

Experimenting with that:

{
	"@context": "https://www.w3.org/ns/activitystreams",
	"id": "https://social.undefinedhackers.net/activity/1337",
	"summary": "!hackers@social.undefinedhackers.net offered to link to !lug@gnusocial.net",
	"type": "Offer",
	"actor": "https://social.undefinedhackers.net/group/hackers",
	"object": "https://social.undefinedhackers.net/group/hackers/relationships/123",
	"target": "https://gnusocial.net/group/lug/relationships"
}

Hi Diogo,

Thanks, I’ll definitely check out Lemmy’s implementation.

Using the word topic might be confusing terminology since it’s used by popular forum systems to denote a thread. I’d like to use topic to refer to the subject matter that’s being discussed and not an individual forum thread.

The reason that I was thinking context might be the right field is based on what I read in ActivityStreams:

The notion of “context” used is intentionally vague. The intended function is to serve as a means of grouping objects and activities that share a common originating context or purpose. An example could be all activities relating to a common project or event.

In the case of communities and forums, I would consider topic to be subject matter:

{
  "type": "Topic",
  "id": "https://activitypub-server.com/topic/programming",
  "name": "Programming",
  "summary": "All discussions centered on programming"
}

And individual services (ones residing on a server) would then specify that they may accept content based on that topic:

{
  "type": "Service",
  "id": "https://yuforia.com/forum/programming",
  "name": "Talk about programming and system architecture",
  "context": [
    "https://activitypub-server.com/topic/programming",
    "https://activitypub-server.com/topic/system-architecture"
  ]
}

As I’m working on my implementation, I’m trying to stick as closely as possible to what ActivityPub already provides since the way a social profile works is very similar to how a forum works. However it may be completely unavoidable (or even advisable) to give community discussions their own AP terminology.

Oh, well, in the spirit of Activity Vocabulary, I think I would instead use a “TopicTag” for that.

Note that Groups are fundamentally different from tags tho (or lists/collections, for that matter). Rozzin explains very clearly the differences in this #software:andstatus Groups issue: Add Group support · Issue #248 · andstatus/andstatus · GitHub

This proposal doesn’t want to change this “mailing list nature” of Groups. #software:gnu-social groups in v3 will be the same as they were in GS version 2. We are first bringing it to ActivityPub federation (Announcing what arrives its inbox to its followers collection), and only after adding this optional extra functionality.

The proposed functionality serves two distinct purposes:

  • Allow a Group Actor A to state that would like announcing to a different Group Actor B (it’s resembles A telling B: would you like to follow me? (Offer{Follow}), but different of that) - either because the group owner did it or because a setting such as gs:unbound is enabled;
  • gs:unbound: Opportunistically maximize these relationships.

With gs:unbound, an aim would then be to have this more resilient Group that despite a server going offline, still federates properly because it is announcing to all known concerned group actors (which then announce their inbox news to its person followers).

Such topic tag could look like this:

{
  "@context": "https://www.w3.org/ns/activitystreams",
 "actor":"http://example.org/actor/sally",
 "to": ["https://chatty.example/ben/"],
  "type": "Note",
  "content": "hello, world.",
  "tag": [
    {
      "type":"TopicTag",
      "id": "http://example.org/topics/gnu",
      "name": "GNU"
    }
  ]
}

If the receiver doesn’t accept a certain TopicTag, it could then identify the forbidden tag from its name property and reject (or only accept a specific set of tags instead).

Tags (as well as your suggestion of using context) is already dissociated from a specific server, which I think is part of what you want. I wouldn’t use context for topics due to two reasons:

  • It states “…grouping objects or activities that share a common…” - I don’t think you’re grouping anything here?;
  • I think a tag expresses this better.

With tags you can also scale it with tags collections where an actor could add a tag to your note (an ideia GNU social has in its backlog to think and maybe implement), etc. :slight_smile:

Oh I didn’t think of the tags field - that makes a lot of sense and you are correct in that I’m looking for something that can represent a community that is dissociated from a specific server. I was thinking that Topic would be an Actor as well and thus have followers - which would be a method of discovery between servers. This is still a centralized model, but eventually (once enough participants in the network reach a critical mass) discovery could be untethered from the centralized Topic authority.

I think that the context field is underutilized and is a good fit for distributing content across servers. One of things I am struggling with is whether Topic is a good representation of a distributed community or if there should be something like a Community resource for such a thing.

Initially I thought Topic was better just because it’s a more ephemeral concept, so when it comes to distributed content, that just seems like a natural fit.

A lot of it comes down to semantics but a Community can represent a number of individual subject topics so it seems like an inversion of the Topics model. That may work well with topic tags representing subject matter and a Community resource representing a distributed model across servers.

There’s no reason that TopicTags couldn’t be an Actor and that could have the associated followers along with it. I do get the impression that AP may need a resource type that represents subject matter.