ActivityPub specification already says it in section 5.2 Inbox: āThe inbox stream contains all activities received by the actor.ā. Why it should be a profile?
This also seems to be described in the spec.
Exactly. Either you ask implementers to copy Mastodon behavior bug-by-bug, or you create a profile by arbitrarily picking micro-blogging features. The latter might be useful, but then it is not clear why you insist on calling it āMastodon profileā and not āmicro-blogging profileā.
This is the level on which this work should be done. Emoji reaction is a singular feature, it canāt be broken down into smaller parts. Why it is a profile though?
Implementations MAY use the presence or absence of specific collection to determine whether the actorās server supports features that depend on that collection and alter their UIs accordingly.
This idea can be generalized further, to using other kinds of properties for feature detection.
Call it the M Protocol, that Mastodon and many other software implementations use to interoperate, if that naming makes it easier for you to separate protocol from implementation of the protocol.
how a ānotification profileā differs from 5.2 Inbox
a ānotification profileā or āminimal profileā would signal that there should be no side effects; the AP message represents something that happened in the past, not a command to do something. for example, if you receive a Create notification, then do not attempt to cache the object, or convert it to a status, or anything else ā once you add the notification to the inbox, itās a no-op.
GET /resource HTTP/1.1
Host: remote.example
Accept: application/activity+json
{
"id": "https://remote.example/resource"
"inbox": "https://remote.example/notifications",
"summary": "This is a resource with an ldp:inbox that accepts Linked Data Notifications. It does NOT implement any side effects described in ActivityPub or in any other specification."
}
POST /inbox HTTP/1.1
Host: remote.example
Content-Type: application/activity+json; profile="https://w3id.org/fep/xxxx/profile/notification"
Link: <https://w3id.org/fep/xxxx/profile/notification>; rel=profile
{
"actor": {
"type": "Person",
"name": "a",
"url": "https://trwnh.com"
},
"type": "Create",
"object": {
"type": "Note",
"url": "https://trwnh.com/notes/1"
},
"to": "https://remote.example/resource",
"summary": "a created a note. (this is intended as a passive notification that has no other side effects.)"
}
HTTP/1.1 200 OK
the āresource managementā or āremote c2sā profile
it is not.
you may be thinking of what happens when an Activity is posted to an outbox, not what happens when an activity is posted to an inbox. the activitypub spec has two separate sections for c2s activities and s2s activities.
for example, c2s Create says this:
The Create activity is used when posting a new object. This has the side effect that the object embedded within the Activity (in the object property) is created.
When a Create activity is posted, the actor of the activity SHOULD be copied onto the objectās attributedTo field.
A mismatch between addressing of the Create activity and its object is likely to lead to confusion. As such, a server SHOULD copy any recipients of the Create activity to its object upon initial distribution, and likewise with copying recipients from the object to the wrapping Create activity. Note that it is acceptable for the objectās addressing to be changed later without changing the Createās addressing (for example via an Update activity).
but s2s Create says this:
Receiving a Create activity in an inbox has surprisingly few side effects; the activity should appear in the actorās inbox and it is likely that the server will want to locally store a representation of this activity and its accompanying object. However, this mostly happens in general with processing activities delivered to an inbox anyway.
notice that the s2s Create does not create the object.
so when i perform the following POST to an inbox (not an outbox!), by default, the object will not be assigned an identifier; the payload will not be mutated in any way; no further processing actions occur.
if we define a profile for resource mangement, then it becomes semantically clear that the intent of the activity is to manage resources and not to serve as a bare notification.
GET / HTTP/1.1
Host: storage.example
Accept: application/activity+json
{
"id": "https://storage.example"
"inbox": "https://storage.example/inbox",
"summary": "This is a storage service with an ldp:inbox that accepts ActivityPub messages with Create/Update/Delete/Add/Remove, but applies the C2S side effects instead of the S2S side effects."
}
OPTIONS /inbox HTTP/1.1
Host: remote.example
HTTP/1.1 200 OK
Allow: GET, HEAD, OPTIONS, POST
Accept-Post: application/activity+json; profile="https://w3id.org/fep/xxxx/profile/resourceManagement"
POST /inbox HTTP/1.1
Host: storage.example
Content-Type: application/activity+json; profile="https://w3id.org/fep/xxxx/profile/resourceManagement"
Link: <https://w3id.org/fep/xxxx/profile/resourceManagement>; rel=profile
{
"id": "https://trwnh.com/some-activity",
"actor": {
"id": "https://trwnh.com/actors/me/index.as2.json",
"type": "Person",
"name": "a",
"url": "https://trwnh.com"
},
"type": "Create",
"object": {
"type": "Note",
"url": "https://trwnh.com/notes/1"
},
"to": "https://storage.example/inbox",
"summary": "a created a note. (this is intended to also store the Note and the Create on storage.example)"
}
HTTP/1.1 201 Created
Location: https://storage.example/07cb49a5dca1ef2b
GET /07cb49a5dca1ef2b HTTP/1.1
Host: storage.example
HTTP/1.1 200 OK
Content-Type: application/activity+json
{
"id": "https://storage.example/07cb49a5dca1ef2b",
"alsoKnownAs": "https://trwnh.com/some-activity",
"actor": {
"id": "https://trwnh.com/actors/me/index.as2.json",
"type": "Person",
"name": "a",
"url": "https://trwnh.com"
},
"type": "Create",
"object": {
"id": "https://storage.example/c7304d4a5fabe02c",
"type": "Note",
"url": "https://trwnh.com/notes/1"
},
"to": "https://storage.example/inbox",
"summary": "a created a note. (this is intended to also store the Note and the Create on storage.example)"
}
why profiles at all
instead of asking implementers to copy Mastodon bug-for-bug, you donāt āarbitrarily [pick] micro-blogging featuresā, you find a common baseline that describes the behaviors encompassed by the profile. for example:
Create creates a Status if and only if:
actor is present
type is present
object is present
published is present
type equals or includes Create
actor.id == object.attributedTo.id
object.type == Note
published is within a 12 hour window of the current instance server time
ā¦
ā¦
ā¦
[the exact set of requirements to get Mastodon/etc to not drop your activity on the floor is an exercise left to the reader. this varies depending on who you target for compatibility.]
you might call this a āfeatureā for authoring a post. i call it a āprofileā because it has to do with semantic processing of the message, not how it gets represented in the UX at the end. as demonstrated above, there are multiple ways to interpret and process a Create, and the purpose of the profile is to modify the semantics and processing rules. the end result of the message is a behavior ā āif I send a Create of a certain shape, it will be interpreted in a specific way and have specific side effects.ā the behavior here is generating a status and attaching it to an account, which is not the same as creating an object and attributing it to an actor. Statuses are a specific entity; they are specified by Mastodonās documentation. Likewise for Accounts. There are differences between Statuses and Objects, and there are differences between Accounts and actors. the work being proposed and described here is to identify those differences, and then identify how broadly across the āfediverseā they can be applied.
the āfeatureā of an āemoji reactā can be considered a āprofileā of the Like activity. this is because it both extends and restricts the semantics of a Like activity. for example, the basic interpretation of a Like activity in the āMastodon profileā is that content gets ignored. if you instead apply the āemoji react profileā to the Like activity, you are allowed to include content, BUT that content MUST be a Unicode emoji or otherwise it MUST be the name of a toot:Emoji in tag. so for the following activity:
{
"actor": "https://someone.example",
"type": "Like",
"object": "https://local.example/some-object",
"content": "That was an excellent post! I very much enjoyed it, and I enjoy your writings in general.",
"to": "https://local.example/someone"
}
by the āmastodon profileā, you have the following behaviors:
it gets converted to a ālikeā entity where the like is from the Account https://someone.example for the Status https://local.example/some-object
however, if https://someone.example does not fit the requirements for an Account, the entire activity will be dropped.
if https://local.example/some-object is not local, the entire activity will be dropped.
despite being addressed only to https://local.example/someone, it will in fact be shown publicly to anyone who loads the Statusās list of likes.
content will of course be ignored.
but the activity is generally considered āvalidā by the āmastodon profileā, because it fulfills the requirements.
meanwhile, if you try to process it according to the āemoji react profileā, this Like activity would actually be invalid and might be dropped. or otherwise it would fallback or degrade to a āmastodon profileā Like activity. or perhaps something else entirely. the point is that you have no way of knowing before sending the activity, unless you profile every single software in the fediverse. what do you expect to happen when you send someone a Like? do they even support Likes? which properties are required? what must or must not their values contain? there are a lot of unanswered questions.
right, i should clarify that when i say āmastodon profileā i mean ideally what is described in ActivityPub - Mastodon documentation which despite being titled āactivitypubā is in fact a set of additional requirements on top of activitypub ā and i use this as an example simply because itās one of the better-documented list of extra requirements.
I neglected to mention this before, but in Linked Data Notifications there is a link relation of http://www.w3.org/ns/ldp#constrainedBy that seemingly could help here:
Inbox URLs can announce their own constraints (e.g., SHACL, Web Annotation Protocol) via an HTTP Link header or body of the resource with a rel value of http://www.w3.org/ns/ldp#constrainedBy. Senders should comply with constraint specifications or the receiver may reject their notification and return an appropriate 4xx error code.
it relies on a lot of out-of-band knowledge, so it isnāt very useful for validating your payloads ahead-of-time (as SHACL would allow you to do).
You also end up with a potential proliferation of these āconstraint URIsā which is not so much a problem for humans as it is a problem for machines.
Constraints may vary over time and thus should be versioned. This means even more URIs to deal with.
There is no inherent decomposition possible into separate features, since there is no expectation that the link resolves to anything machine-usable.
The scope of this link relation is more closely tied to validating payloads than it is describing side effects or behaviors.
ā¦but at the very least, itās worth bringing it up as prior art. Solid Protocol alludes to this briefly but still doesnāt define it.