w3c / activitypub

http://w3c.github.io/activitypub/
Other
1.21k stars 77 forks source link

6.3.1 Partial Updates: Incompatible with JSON-LD #396

Closed steve-bate closed 4 months ago

steve-bate commented 11 months ago

when the value is the json null type; this means that this field should be removed from the server's representation of the object.

The issue is that JSON-LD processing will remove the null-valued property. This make the null-valued property ineffective as a "remove property" instruction.

JSON-LD 1.1 Specification:

A key-value pair in the body of a JSON-LD document whose value is null has the same meaning as if the key-value pair was not defined.

I'm guessing the current partial update algorithm was based on RFC7386. That technique works with JSON, it does not work with JSON-LD.

dmitrizagidulin commented 11 months ago

@steve-bate Thanks for bringing up this question. This is subtle, so we should probably clarify it in the spec.

I think the current wording of Partial Update IS compatible with JSON-LD.

This is because - the server applying the partial update (the JSON Merge patch) applies it in its original compact form, not expanded JSON-LD form. So, the procedure is - server receives the partial update object (which is a JSON-LD object in compact form), and applies the partial update object to the existing object, JSON Merge style. Any JSON-LD Processing of the update object (such as, for example, to check a Data Integrity signature that involves RFDC) is done in parallel by the server (for example, to decide whether to throw an error if the signature does not check out).

May be worth adding an example that contains a partial update object, the existing object, and the result.

nightpool commented 11 months ago

hmm, this does seem like a contradiction with ActivityStreams Core section 2.1 though:

The serialized JSON form of an Activity Streams 2.0 document must be consistent with what would be produced by the standard JSON-LD 1.0 Processing Algorithms and API [JSON-LD-API] Compaction Algorithm using, at least, the normative JSON-LD @context definition provided here.

That said, I'm having a hard time finding where in the JSON-LD processing algorithms or API the actual removal of the null value happens. For example, in the node objects section on parsing, I find this:

image

which seems to indicate that null is a valid value at least at the JSON-LD Document stage, even though this contradicts the general advice given earlier that JSON-LD processors "ignore" nulls. I think it's reasonable then to interpret that earlier quote ("has the same meaning as if the key-value pair was not defined") more as semantic advice on how to interpret a document rather than an actual dictum related to processing a JSON object into a JSON-LD Document. Nowhere in the actual data model or algorithms could I find a place where the nulls should be explicitly removed by a JSON-LD processor.

Although sure enough nulls do get removed by the JSON-LD playground:

image
steve-bate commented 11 months ago

Although sure enough nulls do get removed by the JSON-LD playground:

Yes, I saw that behavior in JSON-LD playground and also in Python rdflib library in the context of the Vocata server that processes ActivityPub as JSON-LD.

Interesting. There was a note in the 1.0 spec editor’s draft that was very explicit about it. Maybe they thought the “has the same meaning as if the [body] map entry was not defined” was clear enough in the final specs? I assumed that was the reason for the behaviors I saw in rdflib and the JSON-LD Playground. But, I agree, I haven’t been able to find an explicit mention of it in the algorithms themselves.

steve-bate commented 11 months ago

the server applying the partial update (the JSON Merge patch) applies it in its original compact form

This doesn’t seem correct to me. AS2 requires that published messages are compacted according to the AS2 conventions, but I’ve seen nothing that requires a server to process specific incoming AP messages (or one specific message in this case) as plain JSON even if otherwise they are doing full JSON-LD processing.

evanp commented 10 months ago

I'm unsure about how to address this issue. Clearly, at least some JSON-LD tools will elide out null values, so a processor using one of those tools will not receive the "null" versions.

One possible way to thread the needle is to treat the Update object not as content per se, but as a delta on the content, which doesn't necessarily need to match the JSON-LD process, but could be plain old JSON.

I think the next step may be an Erratum, or a note in the Primer about this issue and perhaps others with JSON-LD processing, and perhaps a future change to the specification that may allow other values in the Update object, or even a completely different activity (Patch, maybe?).

steve-bate commented 10 months ago

I'm unsure about how to address this issue.

One possibility is to update the spec (if the WG is chartered) so that the C2S Update activity works the same as the S2S Update (full replace, instead of partial). That would eliminate the issue.

JSON-LD 1.1 added JSON Literals (@json). The following context extension does work, but it feels very awkward...

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
       "object": {
         "@id": "as:object",
         "@type": "@json"
       } 
    }
  ],
  "type": "Update",
  "object": {
    "summary": null
  }
}

expands to...

[
  {
    "https://www.w3.org/ns/activitystreams#object": [
      {
        "@type": "@json",
        "@value": {
          "summary": null
        }
      }
    ],
    "@type": [
      "https://www.w3.org/ns/activitystreams#Update"
    ]
  }
]

and compacts to the original document. However, the special "object" override would be required exclusively for a C2S Update and no other activity.

trwnh commented 10 months ago

i would say that making c2s and s2s behavior consistent is the best option we have. partial updates always felt like a bit of a hack, as if you miss some partial updates, you will almost certainly end up with an object state that doesn't represent any valid object revision. with full updates, if you miss some updates, you will at least have some valid revision of the object. therefore, i think we should consider an errata and also consider deprecating this functionality. even right now, clients would theoretically not be able to guarantee that a partial update will work as expected, so the primer should probably caution against using this mechanism as well.

trwnh commented 4 months ago

why was this issue closed? it seems to be unresolved still, as far as i can tell…

On Sun, May 19, 2024 at 07:50 Steve Bate @.***> wrote:

Closed #396 https://github.com/w3c/activitypub/issues/396 as not planned.

— Reply to this email directly, view it on GitHub https://github.com/w3c/activitypub/issues/396#event-12858371737, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACQ5OX2YYMHO5QJHCJFDI33ZDCNZTAVCNFSM6AAAAAA6I6ZBPOVHI2DSMVQWIX3LMV45UABCJFZXG5LFIV3GK3TUJZXXI2LGNFRWC5DJN5XDWMJSHA2TQMZXGE3TGNY . You are receiving this because you commented.Message ID: @.***>