S2S Create Activity

The same question is valid for objectIds.
I have just read the specifcaton again, but I can’t find any reference to it.

*the server will want to locally store a representation of this activity and its accompanying object. *

So that makes only sence, if the activity and the object is accessible on that server. And if i understood linked data right, the id is the url ob the activity/object. And the it is different on servera and serverb.

But if it is different, how can i find the object to update when receiving an update activity?

Do i have to save the original id in a filed like “origin” ? But the description of “origin” says, that is not ok to use it for that case.

I miss a property in ASObject therefore.

7.2 Create Activity

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.

7.3 Update Activity

For server to server interactions, an Update activity means that the receiving server (Title: SHOULD) SHOULD update its copy of the object of the same id to the copy supplied in the Update activity. Unlike the client to server handling of the Update activity, this is not a partial update but a complete replacement of the object.

Could be a way:
https://schema.org/sameAs
https://www.w3.org/TR/owl-ref/#sameAs-def

The ID, when present, is always immutable.

If a peer gives you something with ID http://server_a.com/max/activity_0815, you always continue to reference the content as having ID http://server_a.com/max/activity_0815. That means you can have an inbox collection for server_b like:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "OrderedCollection",
  "totalItems": 4,
  "orderedItems": [
    "https://foo.bar/baz/1",
    "https://server_a.com/max/activity_0815",
    "https://example.com/something/else/123",
    "https://server_b.com/max/activity_0004"
  ]
}

Two ids of different values really do mean they are different.

1 Like

Hey CJ, agreed, what confuses me is the hash fragment.

Two id s of different values really do mean they are different.

exept of fragment identifiers, is that correct?

See also

You’re not alone. :slight_smile: Me too.

Depends on who you ask.

This is an area of elbows and razor blades so I personally avoid sending fragments for IDs entirely. Since it’s unclear what to do about incoming fragments, I believe I have it so that go-fed just passes them through*. My rationale is that I’ve seen fragments used to specify fields within an ActivityStream via some sort of JSON-LD referencing, but go-fed doesn’t do JSON-LD processing, so no need to touch the fragment.

*For the S2S case. For incoming-dereferencing purposes, I think for mastodon compatibility, I erase any fragments (ex: #main-key) before database retrieval because of the same “I don’t do JSON-LD processing” rationale above, and I don’t want to fail Mastodon requests because they have that extra fragment.

1 Like

But this sentence is confusing me:
“and it is likely that the server will want to locally store a representation of this activity and its accompanying object”
(see: 7.2 Create Activity)

You are right and this is absolutely meaningfull in context of linked-data. (expect caching)

Who is able to update objects?
Actor Max creates an activity in he’s outbox:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Create",
  "id": "https://example.com/max/activity_7287374",
  "actor": "https://example.com/max",
  "object": {
    "id": "https://example.com/max/task_72",
    "type": "Task",
    "status": "OPEN",
    "assignee": "https://anotherone.net/thomas",
    "to": ["https://anotherone.net/thomas"]
   },
  "to": ["https://anotherone.net/thomas"]  
}

And now Thomas is fulfilling the task and change the status to “DONE” then this activity will be in Thomas’s outbox:

{
	"@context": "https://www.w3.org/ns/activitystreams",
	"type": "Update",
	"id": "https://anotherone.net/thomas/activity_8888888",
	"actor": "https://anotherone.net/thomas",
	"object": {
		"id": "https://example.com/max/task_72",
		"type": "Task",
		"assignee": "https://anotherone.net/thomas",
		"status": "DONE",
		"to": [
			"https://example.com/max"
		]
	},
	"to": [
		"https://example.com/max"
	]
}

did i miss something in the specification? i don't remember it saying anything about who can update or delete objects.

Because i store the whole activitypub things in an RDF store, i also has to save the object “https://example.com/max/task_72” in the repository/store of “https://anotherone.net/thomas”. It’s part of the activity, that i have to save. and it’s a new version of “https://example.com/max/task_72”.

It’s a bit confusing to do this with the same id?! mabye only in my head. To me it sounds more familiar to save a copy with a reference to the original.

You have a right to cache the payload, unmodified. So you’re correct, server_b will locally store federated payloads from server_a, meaning it is up to your specific application whether you want your app’s logic to:

  1. Store everything ever sent to you and rely heavily on your cache; or
  2. Just store the IRIs and then re-fetch from a peer server whenever you need the body of the object (no caching); or
  3. something in between

That is application-specific. In today’s software, typically only the original actor sends an Update Activity – if the software even allows Updates at all.

The question of “who can do what” is again, unfortunately, application specific. The Update and Delete Activities are sent out to allow coordinated “cache control” of these copies living in other federated peers. Some applications skip the Update logic and only federate Create and Delete.

I think a key point of confusion may be: In your example, you have a cross-instance federated Update. That is, https://anotherone.net/thomas is attempting to Update something originating from https://example.com/. This is not the simple case, but a very gnarly case due to how IRIs today are coupled with their originating server. I think there are discussions on this SocialHub going into great debate trying to solve this kind of general problem (“sending an activity about data living on another instance”) but I’d propose excluding it for now, and revisiting it later.

With that in mind, that means an app’s primary focus is going to figure out if it should let only the original actor also send an Update about the data it “owns” – letting only https://example.com/max send an Update for https://example.com/max/task_72 – or allow anyone on https://example.com send that Update. I can’t remember off the top of my head if some peer software already bakes that assumption into their processing of incoming federated activities, in which case it is also a compatibility problem now.

One point of detail: the Activity may have the actual data you’re interested in (Task, in this case) embedded in its body. I think most implementations rely on IRI indirection here. For example, a complete discovery round of fetching could look like this:

  1. Fetching https://example.com/max/outbox may yield:
{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "OrderedCollection",
  "totalItems": 4,
  "orderedItems": [
    "https://foo.bar/baz/1",
    "https://server_a.com/max/activity_0815",
    "https://example.com/something/else/123",
    "https://server_b.com/max/activity_0004"
  ]
}

2a) You then iterate – I’ll just go through one iteration here – and fetch the first orderedItem:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "type": "Update",
  "id": "https://foo.bar/baz/1",
  "actor": "https://foo.bar/thomas",
  "object": "https://example.com/max/task_72",
  "to": "https://example.com/max"
}

2b) You then fetch https://example.com/max/task_72 and obtain the latest version of it (note: this will also be the same payload when fetching the Create.object for this task):

{
  "id": "https://example.com/max/task_72",
  "type": "Task",
  "status": "DONE",
  "assignee": "https://anotherone.net/thomas"
}
  1. If still iterating, go to 2a.

Ignoring the cross-federated update, the simple path is: each instance of federated software is able to “own” and operate on (update and delete) their own data, but share it. Peers receiving that data can then generally generate new data in response to such data, and also share it. They can also locally delete it (ex: moderation) but it does not result in mass censorship for other federated software instances.

I’m not sure what interactions you’re interested in, but if that previous paragraph is insufficient for your use-cases, you’re not alone. Great questions!

Yes, i also have the feeling that rather few think in triples. but i don’t want to start parsing and interpreting json. in my ideal case, the incoming json becomes a list of triples as quickly as possible. :wink:

That will be a problem :wink: We currently implementing a taskprocessing mechanism, that is a main part of our architecture. ok, for now all actors will be in one instance, but i don’t want to make any exceptions as far as possible. an actor is an actor, no matter on which instance. otherwise it will be chaotic.

But i see a lot of compatibilty problems (a huge amount) in near future. i feel already in there. the federation seems to work for some simple usecases and some simple Notes. but we are far away from building federated applications.

We will see, either i/we fail or we are among the first :wink:

Unfortunately, what i will have to do is rely on our implementation and care little about others. how our interpretations are then compatible remains to be seen.
I can do no more than try to clarify questions here in the socialhub.
It is and remains exciting

1 Like

^ Thats somehow wrong, because the object in the activity https://anotherone.net/thomas/activity_8888888 should not have the same id! It’s a new version of https://example.com/max/task_72 version handling maybe a problem :wink:
Because if i save the object above in my system there is a timerange where two objects in two instances life with the same id in different state.

Exactly.
If I would only read the specification, I understand that the id must be
either null or it must be a “unique global identifier” which is a “Publicly dereferencable URI".

Maybe instead of ‘users’ one of the ‘authors’ could make clear whether
https://alyssa.cat#elephant and
https://alyssa.cat#parrot

are the same id or a different id

An authoritative statement would be wonderful
@rhiaro

:slight_smile:

@Sebastian you are Hijacking the thread :wink:

On the whole @naturzukunft you may be interested in @cwebber 's work on Spritely which perhaps fits better with some of the expectations you’ve laid out that I’ve disappointed.

Yeah this is why some softwares do not support sending the Update activity for certain kinds of content. But you’re right, there is a slow cache-consistency problem. Imagine if we federated via ActivityPub over sneakernet… I go sailing and type up a bunch of notes, including Updates to things you already have cached, and I generate activities, but I don’t have internet access. A ship passes by, and I can federate with them. They have the Update, no one else does. That ship can carry it further to share with the rest of the world, as could mine. ActivityPub accommodates this slow eventual consistency, and can survive divisions of the network (and heal when they’re re-connected).

Apps may demand real-time “global state”, and this is the key tragedy of Blockchain-like decentralized thinking. Trying to have decentralization but also demand global consistency. That is not needed in federation: decentralization, with a window into “the world” and yet acknowledgement there’s more out there that we don’t know. Perhaps a little too philosophical.

:slight_smile: A lot of people wish to remain “compatible with the Mastodon-flavor of ActivityPub”, but it is certainly not required.

FYI ForgeFed had a similar problem and solved it using Offer flow:

The offer flow begins with an Offer activity, in which object is the object being offered for publishing, and target indicates under which list or collection the sender would like the object to be published, if the target actor accepts the offer and publishes it.

Thus, across federating instances, https://example.com/max can Offer something to https://anotherone.net/thomas, then Thomas can Accept it and then do the usual ActivityPub behavior.

3 Likes

i have to sleep over the whole stuff a few nights :wink:

1 Like

ok, now i stuck with the next question ,-)
if i save only the id’s of the activities in the inbox of ActorA, i have to read the ‘graph’ of the activity, if the ActorA wants to see/process it. But therefore the ActorA needs to have an Oauth2 token ?!

Or how should i show the inbox to ActorA ?

I have to had a cache ;-(

Fredy

Yes either a local cache (probably based on the HTTP caching headers) or attempt to dereference over the network each time – expensive and not guaranteed server availability.

How can that work? The remote resources are secured, so without authentication you cannot get the ressources. and in the inbox there are a ressources from a lot different servers/accounts.
Is there S2S Server based wayß an alternative for OAuth2 ?

HTTP Signatures is a community-adopted solution to handle the problem “How to associate a particular HTTP request with a particular Actor in an authenticated manner”. But im sure there are other solutions – could be OAuth2 – but would require more thought and would not be compatible with the Mastodon flavor of ActivityPub.

Note that I entertained the idea of using OAuth2 in the federated context to do “Hi server Z, I am X from peer server Y and want you to delete your cache data about me” in this but it turns out that particular problem doesn’t really have a good solution – so that post is ignorable. I mention it to avoid confusion over any OAuth2 + AP searches you may do – you’re focused on a totally different problem.

1 Like

I have visualised this a little