FEP-34c1: Collection Filtering using TREE Hypermedia Vocabulary

FEP-34c1: Collection Filtering using TREE Hypermedia Vocabulary

Hi everyone,

I’d like to present FEP-34c1 for discussion. It proposes a standard way for ActivityPub clients to request filtered views of Collections using the TREE Hypermedia Vocabulary.

The problem: ActivityPub defines no mechanism for clients to request filtered subsets of Collections. Building a Home Timeline requires fetching the entire inbox and filtering
locally.

The approach: Clients POST a JSON-LD FilterRequest with TREE relations (tree:path, tree:value) to a filter endpoint. Relations are AND-combined, multiple values are OR-combined,
and special placeholders like as:following are resolved server-side. The response is a standard OrderedCollectionPage with cursor-based pagination.

This covers Home Timeline, Mentions, Private Messages, and more.

Links:

Feedback welcome — especially on relation type coverage, the POST-based approach, and multi-path semantics.

I think there are multiple problems with this suggestion:

  1. POST behaviour to Inbox/Outbox collections is already specified very clearly in the ActivityPub document. Adding something like this to them is incompatible in my opinion.
  2. The TREE specification introduces a lot of additional friction when simpler mechanisms like query parameters are available and would serve equally well. From a separate JSON-LD context being required, to the grammar of the TREE payload itself, it adds up.
  3. Removing elements from an ActivityPub object in my opinion is again contradictory to the specification, where the canonical representation of an object is the document that can be dereferenced from the IRI of the object. Yes, the object’s representation in a collection is not the “canonical one” per my definition, but I think it’s still against the spirit of the ActivityPub spec. Hiding data from the clients is never a good idea and I think encourages data models where elements of an object are harder to compute than others, which I believe should not be the case.

So, I recognize this comment is maybe self serving, as I’m the author of FEP-6606 which offers a simpler mechanism for filtering collections, but I think the only true advantage this FEP-34c1 offers versus FEP-6606 is the capability of better expressing “OR” relationship between different filters.

FEP-6606 can’t express something like to=https://example.com/\~janedoe OR cc=https://example.com/\~janedoe without adding additional query parameter keywords (in this specific case something like recipients=https://example.com/\~janedoe)

In my very biased opinion, the simplicity of the filtering mechanism overweighs this small benefit.

1 Like

The only connection between FEP-34c1 and the activity-pub specification is the extension of collections by a filter property. Everything else should be seen as a supplement that can be implemented, but does not have to be.
The behavior of Activity-pub is not affected by FEP-34c1. I cannot see any violation of the Activity-pub specification here.
FEP-34c1 does not remove properties from objects. Activities are returned in full – it only filters which activities are included in the response, comparable to
pagination.

Both approaches (FEP-34c1 and FEP-6606) are not mutually exclusive.

Not directly related to this FEP, but I was discussing the humble as:Collection yesterday, and in other discussions the AP extensibility mechanism came into focus, and that we tend to mash everything into the ActivityStreams vocabulary. @trwnh in separate discussion mentioned how we are afraid to define our own extensions.

as:Collection is already carrying a heavy burden, where it facilitates core protocol capabilities and at the same time is used to model app designs with various overloaded semantics and additional bells and whistles requirements.

Instead of “Collection filtering” this FEP may be “Filtered collections” and introduce FilteredCollection or something like that. It might even have a CollectionFilter object as a property, so you can easily switch filter strategies and mechanisms.

Yes, it particularly introduces friction where others do not follow the JSON-LD approach, and perhaps the FEP might have a default implementation or minimum profile of sorts that is readily implementable in plain JSON fediverse apps.

Btw, great documentation of the FEP itself, it is well outlined and explained.

It’s fascinating how AI can help with documentation. You have to review it carefully and improve it iteratively, but it’s a huge relief! This means that even I can write things without a compiler :wink:

1 Like

Ha, I did not even think of AI when I wrote that remark. Note that it is a sensitive subject. But given thorough review all will be fine, I gather. :sweat_smile:

[OFF-TOPIC]
It’s not easy for me to say this. But I’m going to say it anyway.
I’ve been using AI intensively for four months now – almost every day. And the longer I do so, the clearer it becomes to me that something I didn’t want to admit for a long time is true:
If you want to change the world, there’s no getting around AI.
Not because AI is needed to do the right thing. But because this is the reality: initiatives for social and ecological change—repair cafés, community-supported agriculture, local food co-ops, projects like gsund.rocks—struggle every day to be heard. With few resources, a lot of passion, and against a world that gives visibility primarily to those who can afford it.
If everyone else is using AI, then these initiatives without AI have even worse odds. And we can’t afford that.
My skepticism hasn’t disappeared. But I can’t imagine a world in which we forego a powerful tool – and then still want to have a fair chance.
Cooperation instead of competition. AI as a tool for change – not against it.

Food for thought. I’ll not go more OT, but this is a good subject for Social coding commons.

there isn’t strictly a problem with using Collection; the problem is with using only Collection and nothing else, for things that are more specific than a Collection. example: imagine if OrderedCollection didn’t exist, and collections that were “ordered” were indistinguishable from “unordered” ones.


i haven’t spent much time reading this fep yet, but a few things stand out to me as weird:

“special casing” as:following and as:followers to mean not the collection but the collection’s items feels like a violation of TREE. the root issue is that collections are indirections for sets of items, but the collection is not the set of items – it is a reification of it. because there is special processing involved with collections, you do not want to use it with tree:path and tree:value. what you should be doing instead is defining a special property which is inherently checking the collection items (paginated or unpaginated). something like _:inCollectionItems maybe.

but with that said… doesn’t TREE already do this?!! you have tree:Collection and tree:member which already exist and make me wonder why you bother specifying the “return type” as as:OrderedCollectionPage… which is itself a little weird because you’re saying it is a “page” that is as:partOf some other collection but it’s somehow not linked to any other pages. this implies paged collections whose pages are unreachable, which is a very discomforting stretch when we already have issues with a lack of clarity regarding paging in the first place.

the TREE solution is to use SHACL shape nodes for this kind of member extraction. we see that SHACL defines property paths for this kind of usage.

{
  "@context": {
    "as": "https://www.w3.org/ns/activitystreams#",
    "sh": "http://www.w3.org/ns/shacl#"
  },
  "sh:path": {
    "@list": [
      {"@id": "as:followers"},
      {"@id": "as:items"}
    ]
  }
}

this [sh:path (as:followers as:items);] form is equivalent to SPARQL path as:followers/as:items. the shortcoming here is that this only works for unpaged followers collections – dealing with paging in predicate paths is a bit more complex. this is a weakness of the as:Collection model where as:items of a as:CollectionPage are assumed to be as:items of the as:Collection that it is as:partOf. you could try to represent it as something like this:

{
  "@context": {
    "as": "https://www.w3.org/ns/activitystreams#",
    "sh": "http://www.w3.org/ns/shacl#"
  },
  "sh:alternativePath": {
    "@list": [
      "@list": [
        {"@id": "as:followers"},
        {"@id": "as:items"}
      ],
      "@list": [
        {"@id": "as:followers"},
        {"@id": "as:first"},
        {"sh:zeroOrMorePath": {"@id": "as:next"}},
        {"@id": "as:items"}
      ],
      "@list": [
        {"@id": "as:followers"},
        {"@id": "as:last"},
        {"sh:zeroOrMorePath": {"@id": "as:prev"}},
        {"@id": "as:items"}
      ]
    ]
  }
}

…with arbitrary complexity due to the paging of the as:Collection, which could go both ways. (this kind of exercise really highlights a lot of the problems with as:Collection as it stands…)

Thanks for the feedback on using as:following and as:followers as placeholders. I’ve addressed this in an update:

  1. Dedicated placeholder properties instead of overloading AS2
  • as:following → fep34c1:myFollowees
  • as:followers → fep34c1:myAudience

The previous usage was semantically incorrect — as:followers denotes the collection itself, not its members. The new properties make the server-resolved semantics explicit and
avoid overloading AS2 vocabulary.

myAudience is intentionally broader than the previous as:followers: the server MUST resolve at minimum the followers collections of followed actors, but MAY also include group
memberships, lists, or other collections the actor is known to be a member of.

  1. Pagination clarification
  • as:next/as:prev are now MUST (standard ActivityStreams pagination)
  • tree:relation entries are MAY (additional boundary values for TREE-aware clients)

This ensures existing ActivityPub clients without TREE support can paginate normally.

Both changes are in the branch, feedback welcome.