Continued from Stricter specifications for pagination of Collections and OrderedCollections - ActivityPub / Client to Server - SocialHub
In the example I referenced, the two objects definitely don’t have the same set of properties or the same values for those properties. Given an existing Note:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.test/note-1",
"type": "Note",
"content": "Hello",
"summary": "A greeting."
},
The “id” property (an alias of JSON-LD “@id”) is the unique URI of a specific object/resource, a Note in this case.
And given a C2S Update activity for that Note:
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.test/update-1",
"type": "Update",
"object": {
"id": "https://example.test/note-1",
"content": "Howdy",
"name": "greeting-note",
"summary": null
}
}
This is a graph with two resources. The first resource is an Update activity. The activity resource references a second resource via the “object” property. The second resource is a… I’m going to call it an update description. It has instructions about how to update the existing Note. In this case, it is instructing the server to modify the “content” property, add the “name” property and delete the “summary” property.
The second resource (the update description) also has an “id” property, which means that’s the URI of that resource. But, of course, it’s not. It’s the URI of the update’s target object. That’s the first problem. I’m suggesting that an activity “target” property should be used for this purpose instead. The update description resource probably doesn’t even need an “id” in most cases. It could be referenced via an RDF blank node.
The second issue is that AP requires all objects to have a “type” property. I left that out of the example intentionally since there is no AP-defined type for an update description (and an extension didn’t feel necessary for the example). Putting “Note” in the type property (JSON-LD “@type”) is not correct. It’s not a Note, it’s an update description.
The third issue is the null value for “summary”. The AP specification says this should be interpreted as a property deletion instruction. However, that doesn’t play well with JSON-LD.
A map entry in the body of a JSON-LD document whose value is
null
has the same meaning as if the map entry was not defined.
The JSON-LD parsers I’ve experimented with (including the JSON-LD Playground) do indeed strip out the null-valued instruction from the expanded Update activity (the “summary” property is dropped).
The fourth issue occurs when the Update subgraph is merged with the existing AP graph. The incorrect URI for the update instructions has undesirable results. You can see this if you simulate the graph in the example by combining the existing note and the activity in a list and entering it into the Playground. You’ll see that the Note IRI now has multiple “content” values. You might be able to do some special processing to compensate for that, but it’s not necessary if the “target” property is used.
There are no examples of C2S Update activities in the specification, so using the “target” property for the update target is compliant AFAICT. The S2S Update is a significantly different scenario.
nonetheless, my take on the Update thing is that it should follow S2S Update semantics.
Are you saying that someone implementing C2S Update behavior should follow the S2S Update semantics? If so, the specification clearly says they are different (partial update versus replacement). There are somewhat different, but similar issues with assigning the “object”'s replacement description with the URI of the replacement target. Your example is fine for one update, but after the second update, both of the previous Update activities will reference the Note state following the second replacement. If someone is looking at the first Update activity it’s not going to be what was originally posted. This is where this topic slightly overlaps with the collection discussion. By using “target” for the replacement target, the historical replacement description (the “object” referent) can remain immutable.
Update should have its object inlined or embedded in its entirety, so that the “complete replacement” logic can be followed as described in the S2S Update section.
Is that always true? What about something like the following?
{
"@context": "https://www.w3.org/ns/activitystreams",
"id": "https://example.test/update-1",
"type": "Update",
"object": "https://example.test/myobject-version-3",
"target": "https://example.test/myobject"
}
This would tell the server to replace the existing “https://example.test/myobject” with the content of “https://example.test/myobject-version-3” (maybe the remote server has a special versioning feature). The object could be inlined as a performance optimization, but it could also be dereferenced from the remote server.