FEP-0391: Special collection proofs

Hello!

This is a discussion thread for the proposed FEP-0391: Special collection proofs.
Please use this thread to discuss the proposed FEP and any potential problems
or improvements that can be addressed.

Summary

Some properties represent special collections, such as:

  • outbox ([ActivityPub][AP])
  • inbox ([ActivityPub][AP])
  • followers ([ActivityPub][AP])
  • following ([ActivityPub][AP])
  • liked ([ActivityPub][AP])
  • likes ([ActivityPub][AP])
  • shares ([ActivityPub][AP])
  • replies (FEP-7458)
  • context (FEP-7888)

Verifying that any given object is part of a special collection is usually only possible by resolving that collection and checking its items one-by-one until the current object is found. This can be inefficient to verify. It would be easier if there was an inverse claim for each claim made about an object being part of a special collection. This FEP aims to define some properties that can be used to make those inverse claims.

cc @Claire @erincandescent @jenniferplusplus @dumspterqueer and i guess everyone else who was involved in the discussion for FEP-5624: FEP-5624: Per-object reply control policies

This FEP is mostly the synthesis of what was discussed there. The only thing missing currently is signalling properties, like whether the object/actor supports generating stamps, whether they automatically or manually grant stamps, hinting who might be approved ahead of time, and so on. I’m also considering whether or not to add explicit “stamp types” like ApproveReply, ApproveLike, and so on; it may or may not be appropriate, given that the current state of this FEP is focused more around verification and validation rather than “approval”. Nonetheless, the current mechanism for detecting a “stamp” is to check if it’s an Add activity and it’s attributedTo another activity. (It may be enough to simply check for attributedTo presence on the Add, or otherwise check if actor == attributedTo. I leave this up to implementers and to the discussion.)

Quick summary:

  • When an activity that has a side effect of adding something to a special collection is received, you respond with an Add that is attributedTo the activity with the side effect.
  • When you receive an activity that is attributedTo one of your activities, you Update your activity to include the received activity as the result of your activity.
    • If your activity was a Create, then:
      • if the target of the stamp was context, then Update the object to add a contextProof.
      • if the target of the stamp was inReplyTo.replies, then Update the object to add an inReplyToProof.
1 Like

Verifying presence in outbox

Claim
Activity <A>'s actor (<A>.actor) is actor <B>
Inverse claim
Actor <B>'s outbox collection (<B>.outbox) contains activity <A>

This is not particularly useful to prove.

This would be useful for verifying the attribution of the activity to the actor (https://github.com/w3c/activitypub/issues/432#issuecomment-2015521544), because <A> as:actor <B> . does not necessarily imply <B> as:outbox/as:items/rdf:rest*/rdf:first <A> . and it is possible that activity <B> is making a false claim in order to impersonate actor <A>.

activities are generally verified by either fetching the activity directly or by deferring to the http signature at time of delivery or by using an embedded ld signature/proof. therefore proving an activity is in the outbox/inbox is not very useful; you usually only care about the activity itself, and the outbox is just a discovery endpoint.

one exception i can think of (requires further thought) is using the “stamp” behavior to signal successful delivery, but this risks an infinite loop and also isn’t really a “side effect” of an activity. it’s a side effect of POST to outbox/inbox. so it shouldn’t generate a stamp.

The resulting stamp activity SHOULD be attributedTo the activity that caused the side-effect

It would be better to use another property (e.g. resultOf).

I know that definition of attributedTo property says this is possible, but still, in practice attributedTo is used to specify who owns an object.

The concept of ownership probably deserves its own FEP. For example when a Note is fetched, the client should verify attributedTo to avoid impersonation (by doing the same origin check or by comparing the value of attributedTo with proof.verificationMethod) . As far as I know, this is not described anywhere.

One point of distinction is that this is “attributedTo” on an activity. The ownership is already determined by “actor” property.

The meaning of the property shouldn’t depend on the object type. “attributed to the completion of another activity” is very different from “attributed to the actor”.
Also, how we can determine that given object is an activity? Currently one can’t rely solely on the actor property because some implementations add it to Note objects too (Pleroma). The only reliable way I have found is "has(actor) and not has(attributedTo)".

The domain of actor is explicitly marked as Activity so that would be a bug in Pleroma

EDIT: Stop putting `actor` on non-Activity objects (#3269) · Issues · Pleroma / pleroma · GitLab

EDIT 2: #770 - Stop putting `actor` on non-Activity objects - AkkomaGang/akkoma - Akkoma Development

2 Likes

has(actor) AND ( has(object) OR has(target) ) would work in practice but not in theory (as it would leave out IntransitiveActivity that has neither object nor target, e.g. Question, but Question is treated like an Object anyway so this is kind of a moot point)

1 Like

Well, in an RDF Schema sense IIUC, using a property with a domain of class Activity entails that the subject is of the Activity class. In other words, that means Pleroma’s behavior is semantically equivalent to stating "type": ["Note", "Activity"], which doesn’t make much sense.

(Of course, this is a quite pedantic argument.)

@silverpill Pleroma merged their MR to stop putting actor on objects. I’m not sure if they put attributedTo on their activities, but they shouldn’t / don’t need to do that. Do you know if this is the case?

@trwnh No, I’ve never seen attributedTo in activities.

(btw, the merged commit might have unintended side effects: Stop putting `actor` on non-Activity objects (#3269) · Issues · Pleroma / pleroma · GitLab)

Ahh, attributedTo, my behated…

We started with the author property from AS1.0. Somewhere along the way that got lost, then reintroduced as attributedTo, and the scope got widened so now anything can be attributedTo anything. attributedTo in what sense? Well right now everyone means what AS1.0 called “author” - what we started with - though they probably mean “publisher”,

(What did AS1 implementations mean? That’s actually simultaneously more and less clear. What we today call Create(Note), AS1 would call post(note); there, publisher as the actor of the post activity as distinct from the author of the note makes more sense than it does with Create’s actor vs the note’s attributedTo)

–

Anyway, what I’m trying to get at is that in the road to the creation of AS2.0, there was an awful lot of semantic generalisation. Create is the result of squishing create, post and author together (yes there was also an author activity! no I don’t think anyone had a concrete use case for it or ever used it!). attributedTo is a generalisation of author

Some of this makes sense: if we’re using attributedTo to strictly mean author, we’re probably using it wrong (if you imagine a properly rich implementation of AP by a news site, probably people would want to stuff the publication’s name into the attributedTo property for backwards compatibility, and add a new author property for the actual authors of the article); but you have to wonder how this useful generalisation got extended further to the point the Range of the property is now Link | Object.

The result of this applied to the entirety of AS2 is a deeply, deeply unhelpful and implementer hostile situation where nearly every property applies to any object and can point at any object.

(If I were placed in the position of AS2 spec editor, I think I would look at what variants are used by real world implementations and ruthlessly deprecate every other option)

So while AS2 as written permits this use case, I deeply dislike the use of it (I also dislike the use of the Add activity here, though not as much; as an implementer concern, it results in a proliferation of URI indexes which are annoying to scale in a way that supports tiered storage on long-running instances with growing databases if you have to track the URI of every special collection - especially exacerbated if you have to do so for every post to track the replies collection)

Broadly though, I like the implementation; I just think:

  • We shouldn’t use attributedTo. Yeah, I know AS2 says we can, but that way lies implementer madness; and
  • If we’re using the Add activity, we add some required property to signal the relationship the container has to its’ parent)
1 Like

@erincandescent On the subject of attributedTo… I’m trying to clarify the role of attributedTo’s in authentication and authorization: FEP-c7d3 (discussion). Would appreciate your feedback!

I’d be interested in hearing more about practical examples of “implementer madness”. So far I am unconvinced that it is particularly problematic to use attributedTo on Activities. In fact, I am having trouble thinking of other potential uses for attributedTo on an Activity that aren’t already covered by the use of actor on an Activity — like, does it make sense to “author” an Activity on behalf of some other “actor” perhaps? This example usage feels like it would be best served by a different extension property, perhaps author as you suggest or perhaps something already existing like dc:creator.

To me, the most natural semantics are “(This activity) is attributed to (some other activity).” It gets a little hairy because actor is considered a sub-property of attributedTo… which means you can infer that the Activity is attributedTo the actor, since actor implies attributedTo. To be explicit, this implies that attributedTo has multiple values: one for the actor who performed the current activity, one for the activity that resulted in the current activity. But it would be redundant to declare both actor and attributedTo in every single case. So implementation-wise, you would be able to get away with it, as long as you could identify that attributedTo points to an Activity.

I am not sure we need a resultOf property with largely the same semantics as “attribution”, but I do instead see a separate complication for implementers — what if someone uses attributedTo on Objects to point to the Create activity that was associated with the object? That seems like a valid and perhaps even more fitting interpretation of “attribution”. This runs tangent to the other debate about whether we should be doing all our “post” logic at the Object level or at the Activity level. So again, it looks like authorship is the semantic use case more in need of an explicit property. Madness? This is ActivityPub! :stuck_out_tongue:

This would be convenient to have but IDK about making it required. We are definitely missing a “follow your nose” way of going from a replies or followers or following or likes or shares back to the object or actor they belong to. Less so for context, because you’d have to keep track of context URIs anyway.

Maybe we can do this with attributedTo? Assuming that we say a Collection is “attributed” to an object, that is to say, the object resulted in the creation of the special collection, in the same way that the Create activity resulted in the creation of the object. It’s attributedTo all the way down. (I’m only half-joking!)

If there’s anything to blame here, I’d point squarely toward the circular definition of the attributedTo property. At least with this thought experiment I’m being consistent with my interpretation of “attribution” == “resulting in creation of”. It’s simple causality. If you look up the definition of the word, that’s the sense you get:

attributed (verb)
regard something as being caused by (someone or something).

Re-summarizing the current state of things:

  • We need a way to link related activities together by a causal relationship; currently, this FEP proposes using result.
  • We need a way to signal that something is the result of another Activity; currently, this is done in the FEP by saying that your Activity is attributedTo another Activity. (Another proposal is to use a new property like resultOfwhich is more explicit in its purpose.)
  • We need a way to get from an object to the activity that Created it (and its result); this is not yet addressed, but it spawned discussion above of attributedTo being used to point to the Create activity instead of to the actor that authored it. (Again, another proposal is to define a new property like createdBy or createActivity which is more explicit in purpose.)
    • Authorship information is currently expressed in pretty much every implementation by attributedTo but would probably be better expressed via some other property sharing the semantics of dc:creator or similar. (This may be a non-starter for now, though, as current usage of attributedTo is very deeply entrenched within the implementer ecosystem.)
    • Getting to the Create activity can be sidestepped by using the helper properties inReplyToProof and contextProof as currently defined by the FEP, but it would be broadly more helpful to be able to get to the Create activity anyway, as the Create activity may have more useful / different metadata than the object which was created.

The more general point here being that attributedTo is problematic and doesn’t really have clear semantics, I guess? “Attribution” is defined by causality and/or ascription, but many things often do not have a single cause and cannot be ascribed to a single entity. This is probably the point @erincandescent was trying to make. My view is that semantically, you can “attribute” an object to the actor that created it, or the activity that created it. Those are the two usages that make any sort of sense. But there’s also the concept of “ownership” as FEP-c7d3 by @silverpill tries to define this using attributedTo as well.

The other point which hasn’t been explored in-depth: the purpose of an Add activity is not immediately clear since the target Collection’s purpose or contextual reason to exist is also not clear. This could imply several things:

  • Perhaps the Collection should signal its relation to some other object? repliesOf, likesOf, sharesOf or something along those lines could be used to link back to the object that has the replies/likes/shares collection in the first place. (contextOf doesn’t really make sense as much because the very nature of context is to contain/group anything that declares it)
  • Perhaps the Add should signal this relation instead? You could multitype the Add with other extension types such as AddReply, AddLike, AddShare?

I’m not really a fan of either of the above two points but I don’t have anything better to propose yet.

Can’t edit my last post but I forgot to mention the possibility of an undoneBy or some other way to signal that an Add has been “revoked” and should not be used as a stamp/proof.

Also an alternative approach that I should probably make sure to discuss in the FEP: general query support, e.g. SPARQL or something similar to Smithereen’s collectionSimpleQuery endpoint