fediverse/fep
37
268
Fork
You've already forked fep
100

doc: FEP-c648 Blocked Collection #111

Merged
helge merged 2 commits from evanp/fep:fep-c648 into main 2023年07月05日 09:12:28 +02:00
Contributor
Copy link

Users need to review and revise the list of actors they have blocked. This FEP proposes a new collection property, the Blocked Collection, which contains the actors that a user has blocked.

Users need to review and revise the list of actors they have blocked. This FEP proposes a new collection property, the Blocked Collection, which contains the actors that a user has blocked.
Signed-off-by: Evan Prodromou <evan@openearth.org>
First-time contributor
Copy link

The activitypub-express library (and projects based on it like Immers Space and Guppe groups) implement the blocked collection as well.

Since it wasn't a standard actor property already, it is currently nested under actor.streams. Agree with the proposal to promote it to an actor property, though.

Like in this proposal, we mimicked the followers/following collection by making this a collection of people (in our case, IRIs to actors). However, in retrospect, I think this was a mistake.

With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a terrible server-side heuristic to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person.

Consider specifying the blocked collection as a collection of Block activities instead so that it would contain all the information necessary to manage that collection.

The [activitypub-express library](https://github.com/immers-space/activitypub-express) (and projects based on it like [Immers Space](https://github.com/immers-space/immers) and [Guppe groups](https://github.com/immers-space/guppe)) implement the `blocked` collection as well. Since it wasn't a standard actor property already, it is currently nested under `actor.streams`. Agree with the proposal to promote it to an actor property, though. Like in this proposal, we mimicked the followers/following collection by making this a collection of people (in our case, IRIs to actors). However, in retrospect, I think this was a mistake. With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a [terrible server-side heuristic](https://github.com/immers-space/activitypub-express/blob/e371e9c704b9d8c5da8e30b883665b1e78610a85/net/validators.js#L326-L343) to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person. Consider specifying the blocked collection as a collection of Block activities instead so that it would contain all the information necessary to manage that collection.
Author
Contributor
Copy link

That sounds like a really good point! I'll change blocked from objects to activities. Thanks for the note!

That sounds like a really good point! I'll change `blocked` from objects to activities. Thanks for the note!
Signed-off-by: Evan Prodromou <evan@openearth.org>
Author
Contributor
Copy link

Thanks so much to @syndic-will for the note about activities versus actors. I've updated the proposal to list activities, and tried to give the reason why.

Thanks so much to @syndic-will for the note about activities versus actors. I've updated the proposal to list activities, and tried to give the reason why.
Member
Copy link

This actually raises a similar issue with liked in ActivityPub... there, the liked collection contains the objects, not the Like activities. So the parallel expectation would be to have blocked contain the blocked actors as well.

But it is also a valid and pressing use-case to have access to the original activity. I imagine that this would be accomplished by filtering/querying the outbox, if there were any support for filtering/querying...

This actually raises a similar issue with `liked` in ActivityPub... there, the `liked` collection contains the objects, not the Like activities. So the parallel expectation would be to have `blocked` contain the blocked actors as well. But it is also a valid and pressing use-case to have access to the original activity. I imagine that this would be accomplished by filtering/querying the `outbox`, if there were any support for filtering/querying...
Member
Copy link

With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a terrible server-side heuristic to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person.

Another option might be to send an Undo Block where the Block is inlined or embedded, without an id. Like so:

{
 "actor": <you>,
 "type": "Undo",
 "object": {
 "actor": <you>,
 "type": "Block",
 "object": <some-actor>
 }
}
> With the purpose of being able to manage your blocklist, just having an actor object is insufficient to construct a C2S activity the remove that person from the list. The Undo activity should be used to undo a past Block activity, but to construct an Undo you need a reference to that past Block activity rather than just its object. We ended up with a [terrible server-side heuristic](https://github.com/immers-space/activitypub-express/blob/e371e9c704b9d8c5da8e30b883665b1e78610a85/net/validators.js#L326-L343) to allow sending Undo->Person and have it translate that into Undo->Block by looking up the block activity for that person. Another option might be to send an Undo Block where the Block is inlined or embedded, without an id. Like so: ```json { "actor": <you>, "type": "Undo", "object": { "actor": <you>, "type": "Block", "object": <some-actor> } } ```
Author
Contributor
Copy link

This actually raises a similar issue with liked in ActivityPub... there, the liked collection contains the objects, not the Like activities. So the parallel expectation would be to have blocked contain the blocked actors as well.

followers, following and liked all include objects.

likes and shares all include activities.

Should we change the name of blocked to be blocks or blocklist to make it clear that it includes activities?

> This actually raises a similar issue with `liked` in ActivityPub... there, the `liked` collection contains the objects, not the Like activities. So the parallel expectation would be to have `blocked` contain the blocked actors as well. followers, following and liked all include objects. likes and shares all include activities. Should we change the name of `blocked` to be `blocks` or `blocklist` to make it clear that it includes activities?
Member
Copy link

I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors

For a Client, the main consideration is being able to block and unblock easily, right?

So I guess a similar question is: how might you send an Undo Like with the <actor>.liked collection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in <actor>.streams for Like activities as well? Do you handle <actor>.following and <actor>.followed the same with Follow and Accept Follow, so that you may later Undo or Reject them?

Personally, my mental model assumes that all activities end up in the <actor>.outbox due to C2S. But the <actor>.outbox returns different results based on who's asking. An unauthed request will not return Block activities, but an authed request by <actor> would return them. So I'd favor a blocked which contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities.

I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors For a Client, the main consideration is being able to block and unblock easily, right? So I guess a similar question is: how might you send an Undo Like with the `<actor>.liked` collection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in `<actor>.streams` for Like activities as well? Do you handle `<actor>.following` and `<actor>.followed` the same with Follow and Accept Follow, so that you may later Undo or Reject them? Personally, my mental model assumes that all activities end up in the `<actor>.outbox` due to C2S. But the `<actor>.outbox` returns different results based on who's asking. An unauthed request will not return `Block` activities, but an authed request by `<actor>` would return them. So I'd favor a `blocked` which contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities.
First-time contributor
Copy link

I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors

For a Client, the main consideration is being able to block and unblock easily, right?

So I guess a similar question is: how might you send an Undo Like with the <actor>.liked collection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in <actor>.streams for Like activities as well? Do you handle <actor>.following and <actor>.followed the same with Follow and Accept Follow, so that you may later Undo or Reject them?

@trwnh The fact that many of the standard collections are specified to contain objects instead of their originating activities is what makes a C2S client so difficult to create. It's equally impossible to remove a follow or follower, unless you were to fetch the entire outbox history to track down that original activity, so we have terrible server-side heuristics for those as well.

Personally, my mental model assumes that all activities end up in the <actor>.outbox due to C2S. But the <actor>.outbox returns different results based on who's asking. An unauthed request will not return Block activities, but an authed request by <actor> would return them. So I'd favor a blocked which contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities.

I think the blocked collection is pretty clearly defined as primarily serving the client (if a server needs its own blocklist it can retrieve those any way it wants with no standards needed), and any software that needs the object can simply extract it from activity.object. That's such a simple operation in comparison to the reverse which we all seem to recognize is very difficult - why make it difficult for the primary use case?

> I think from a Server's POV the main consideration is dropping interactions from blocked actors --> i.e. getting a list of all blocked actors > > For a Client, the main consideration is being able to block and unblock easily, right? > > So I guess a similar question is: how might you send an Undo Like with the `<actor>.liked` collection only containing the objects and not the activities? Pinging @syndic-will for their thoughts here... do you put a collection in `<actor>.streams` for Like activities as well? Do you handle `<actor>.following` and `<actor>.followed` the same with Follow and Accept Follow, so that you may later Undo or Reject them? > @trwnh The fact that many of the standard collections are specified to contain objects instead of their originating activities is what makes a C2S client so difficult to create. It's equally impossible to remove a follow or follower, unless you were to fetch the entire outbox history to track down that original activity, so we have terrible server-side heuristics for those as well. > Personally, my mental model assumes that all activities end up in the `<actor>.outbox` due to C2S. But the `<actor>.outbox` returns different results based on who's asking. An unauthed request will not return `Block` activities, but an authed request by `<actor>` would return them. So I'd favor a `blocked` which contains the actors and not the activity, because that's what the server needs to work with. And an alternate mechanism to filter the outbox for certain activities. I think the blocked collection is pretty clearly defined as primarily serving the client (if a server needs its own blocklist it can retrieve those any way it wants with no standards needed), and any software that needs the object can simply extract it from `activity.object`. That's such a simple operation in comparison to the reverse which we all seem to recognize is very difficult - why make it difficult for the primary use case?
Member
Copy link

why make it difficult for the primary use case?

the use case i was thinking of was if actor in blocked a la if object in liked or if actor in followers or if actor in following as the existing/prevailing data model seems to be. having blocks be the "odd one out" makes it confusing. and i'm not sure it would have ever made sense to keep track of Accept Follow activities instead of directly keeping track of followers, for example.

basically, i see the problem you're having, and it is a valid problem, but it is part of an entire class of problems that should be solved with a common mechanism for filtering or querying the outbox for the activity you are looking for. or even filtering or querying any arbitrary collection. otherwise, you could very well imagine a follows collection, an accepts collection, a likes collection which conflicts with the already-existing likes collection, and so on. see FEP-5bf0 for an attempt at addressing this: https://socialhub.activitypub.rocks/t/fep-5bf0-collection-sorting-and-filtering/3095 -- the linked thread discusses query languages like SQL or SPARQL, and the current state of the proposal uses SHACL which i am not familiar with, but the general idea of having querying support makes sense. i could see it being one of the endpoints for the server, perhaps? but that's a different topic...

> why make it difficult for the primary use case? the use case i was thinking of was `if actor in blocked` a la `if object in liked` or `if actor in followers` or `if actor in following` as the existing/prevailing data model seems to be. having blocks be the "odd one out" makes it confusing. and i'm not sure it would have ever made sense to keep track of Accept Follow activities instead of directly keeping track of followers, for example. basically, i see the problem you're having, and it is a valid problem, but it is part of an entire class of problems that should be solved with a common mechanism for filtering or querying the outbox for the activity you are looking for. or even filtering or querying any arbitrary collection. otherwise, you could very well imagine a `follows` collection, an `accepts` collection, a `likes` collection which conflicts with the already-existing `likes` collection, and so on. see FEP-5bf0 for an attempt at addressing this: https://socialhub.activitypub.rocks/t/fep-5bf0-collection-sorting-and-filtering/3095 -- the linked thread discusses query languages like SQL or SPARQL, and the current state of the proposal uses SHACL which i am not familiar with, but the general idea of having querying support makes sense. i could see it being one of the `endpoints` for the server, perhaps? but that's a different topic...
Author
Contributor
Copy link

@trwnh it sounds like you think that this would be the server's internal representation of the blocklist. It's not! It's just the way an API client can retrieve this information.

The server would typically have a representation like an indexed relational database table to quickly look up the block relationship.

We're defining the on-the-wire API, not the internal representation. The main use cases for client apps are 1) view the blocked actors and 2) undo a block. I think we cover that pretty well with this collection.

I'd also say that as a principle developer experience should outweigh conceptual coherence. Parallelism would suggest that blocked would have the same kind of things as followers and following, but in this case we're hearing from at least one dev who found the lack of Activity info hampering.

Another note: I think we could do a separate FEP for ID-less undo. I really like @trwnh 's proposal to Undo a Block without an id but with the right object. We could do that for Undo on Follow, Like, Announce, etc. It's a pretty useful pattern!

@trwnh it sounds like you think that this would be the server's internal representation of the blocklist. It's not! It's just the way an API client can retrieve this information. The server would typically have a representation like an indexed relational database table to quickly look up the block relationship. We're defining the on-the-wire API, not the internal representation. The main use cases for client apps are 1) view the blocked actors and 2) undo a block. I think we cover that pretty well with this collection. I'd also say that as a principle developer experience should outweigh conceptual coherence. Parallelism would suggest that `blocked` would have the same kind of things as `followers` and `following`, but in this case we're hearing from at least one dev who found the lack of Activity info hampering. Another note: I think we could do a **separate** FEP for ID-less undo. I really like @trwnh 's proposal to `Undo` a `Block` without an `id` but with the right `object`. We could do that for `Undo` on `Follow`, `Like`, `Announce`, etc. It's a pretty useful pattern!
First-time contributor
Copy link

Another note: I think we could do a separate FEP for ID-less undo. I really like @trwnh 's proposal to Undo a Block without an id but with the right object. We could do that for Undo on Follow, Like, Announce, etc. It's a pretty useful pattern!

This does sound pretty awesome, and would solve most of the pain points for C2S for us, and there already is a concept of the server filling in partial activities from C2S for Create, so it doesn't seem out of line.

The only one this doesn't cover is removing someone from your followers. We're sending a Reject of the original Follow to communicate this (and using another bad server-side shortcut to find that Follow). I suppose a similar pattern would work, though

{
 "actor": <you>,
 "type": "Reject",
 "object": {
 "actor": <some-actor>,
 "type": "Follow",
 "object": <you>
 }
}
> Another note: I think we could do a **separate** FEP for ID-less undo. I really like @trwnh 's proposal to `Undo` a `Block` without an `id` but with the right `object`. We could do that for `Undo` on `Follow`, `Like`, `Announce`, etc. It's a pretty useful pattern! This does sound pretty awesome, and would solve most of the pain points for C2S for us, and there already is a concept of the server filling in partial activities from C2S for Create, so it doesn't seem out of line. The only one this doesn't cover is removing someone from your followers. We're sending a Reject of the original Follow to communicate this (and using another bad server-side shortcut to find that Follow). I suppose a similar pattern would work, though ``` { "actor": <you>, "type": "Reject", "object": { "actor": <some-actor>, "type": "Follow", "object": <you> } } ```
Sign in to join this conversation.
No reviewers
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
fediverse/fep!111
Reference in a new issue
fediverse/fep
No description provided.
Delete branch "evanp/fep:fep-c648"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?