Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Section 6.3.1 C2S Partial Update property deletion behavior is impossible and should be deprecated #477

Open
trwnh opened this issue Nov 2, 2024 · 18 comments
Labels
Needs FEP Needs a FEP Needs Group Input/Decision Needs Primer Page Needs a page in the ActivityPub primer Next version Normative change, requires new version of spec

Comments

@trwnh
Copy link

trwnh commented Nov 2, 2024

#396 was closed without resolution, so I'm reopening discussion of the unsolved issue.

ActivityPub:

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

@steve-bate:

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.

@evanp:

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?).

@trwnh:

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.


summary

  • Needs Primer: explain the issue with C2S "partial update" and caution against its usage
  • Needs Errata: note in the spec that this behavior is incompatible with JSON-LD and AS2
  • Next Version: consider deprecating this functionality entirely for above reasons (making c2s and s2s consistent, ensuring that Updates leave the object in a consistent state)
@trwnh
Copy link
Author

trwnh commented Nov 15, 2024

additional concern: client-side signing breaks if the server is going to send out a modified activity, for example translating a partial Update (or Patch) into a full Update.

@evanp
Copy link
Collaborator

evanp commented Nov 15, 2024

I think we have four next steps.

  1. Add an erratum that notes that the use of nulls to delete property values from an object simply doesn't work with JSON-LD processors, and since there's no way to ascertain whether a client or server is parsing with JSON-LD or with plain old JSON, and since the spec says everything is supposed to look like compacted JSON-LD, there's no way to use this feature. The correction of the text would be to remove entirely the sentence A special exception is for when the value is the json null type; this means that this field should be removed from the server's representation of the object. We could also note that the original version of the document recommended this, and provide some guidance for servers that receive Update activities with nulls in them.
  2. Defining an extension for an extended activity with a new name, like Edit or Patch, that supports partial updates including adding, updating, and deleting properties. Deleting properties in this structure could use one or more different techniques, such as having a special value like rdf:Nil that represents a deleted property. This would give us the full functionality that was originally described in AP, without the null problems.
  3. Incorporate that extension into the AS2 context, using the extension policy.
  4. Deprecate Update in future versions of AP.

@evanp evanp added Needs Primer Page Needs a page in the ActivityPub primer Needs errata We need to add errata for this Needs FEP Needs a FEP Next version Normative change, requires new version of spec labels Nov 15, 2024
Copy link

This issue has been labelled as potentially needing a FEP, and contributors are welcome to submit a FEP on the topic.
Note that issues may be closed without the FEP being created; that does not mean that the FEP is no longer needed.

@nightpool
Copy link
Collaborator

nightpool commented Nov 15, 2024 via email

@steve-bate
Copy link

The other significant issue with Update for both C2S and S2S is that it conflates the object and target by putting the target URI in the object data. In a Linked Data context that stores activities and has inbox collections (not Mastodon), this means the historical inbox-referenced activities effectively change when updates are processed since the older activity update descriptions reference the modified object's URI. If the URI of the update target were put into the target property, then the inbox history would stay intact and an accurate update history would exist.

(I understand these statements may be confusing if you're not thinking in terms of Linked Data graphs and only considering AP JSON-LD subgraph serializations.)

In a spec revision, I recommend that the target property be used for the update target URI. For backwards-compatibility, Linked Data consumers would need to detect "old style" Updates and move the URI from object to target prior to doing JSON-LD/RDF processing and related graph updates.

Another possibility would be disallow the current style of update. If there were a predicate to indicate replacement (e.g., as:replaces or as:revisionOf), then new versions of objects (with new URIs) would replace previous objects instead of updating them. The entire history could (optionally) be preserved for moderation or other purposes.

@nightpool
Copy link
Collaborator

Can you give a more concrete explanation of why object and target would be treated differently here?

@steve-bate
Copy link

Can you give a more concrete explanation of why object and target would be treated differently here?

In the C2S partial update case, the object is the partial update description. However, AP C2S partial Updates (typically) use the target URI as the id of the update description, which makes no sense.

Example:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://server.example/activity-2",
  "type": "Update",
  "object": {
    "id": "http://server.example/note-1",
    "content": "I like ice cream."
  }
}

Section 6.3 says "The side effect of this is that the object MUST be modified to reflect the new structure as defined in the update activity, assuming the actor has permission to update this object." Again, it doesn't make sense. The object is the update description. Why would that be modified as defined in the update activity?

To be fair, there's no example of a C2S partial update in the spec, so maybe implementors have misinterpreted the requirements. In any case, putting the update target URI in the target property addresses the issue.

Example:

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://server.example/activity-2",
  "type": "Update",
  "object": {
    "content": "I like ice cream."
  },
  "target": "http://server.example/note-1"
}

@trwnh
Copy link
Author

trwnh commented Nov 18, 2024

@steve-bate that's an interesting idea and i hadn't considered it. i guess we could say that the Update.object is in JSON Patch form? or alternatively, we introduce an extension property that has @type: @json and leave Update.object alone. something like

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://server.example/activity-2",
  "type": "Update",
  "object": "http://server.example/note-1",
  "jsonpatch": [
    {"op": "replace", "path": "/content", "value": "I like ice cream."}
  ]
}

i don't particularly like this because i prefer to think of the actual statements more in terms of rdf, so what i'd really like is an "rdf patch" that can be transformed to/from rdf triples. which is what i think Update is intended to be, or could work as.

maybe even instrument could work here?

Identifies one or more objects used (or to be used) in the completion of an Activity.

so you could say something like

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://server.example/activity-2",
  "type": "Update",
  "object": "http://server.example/note-1",
  "instrument": {
    "content": "I like ice cream."
  }
}

in which case, the C2S would need to be reworked to apply instrument as a patch to object. S2S it would "fall back" to

{
  "@context": "https://www.w3.org/ns/activitystreams",
  "id": "http://server.example/activity-2",
  "type": "Update",
  "object": "http://server.example/note-1"
}

for unaware implementations, which would likely just fetch the object from origin again. which also isn't particularly great, since it incurs an extra HTTP request for each recipient. n recipients means n extra requests.

although another caveat: there's also a possible interpretation where a bare id in the Update may be interpreted as removing all properties, since it could be seen as replacing the object with

{
  "id": "http://server.example/note-1"
}

and there is no syntactical difference between this and "object": "http://server.example/note-1".

so i still keep landing on the "cleanest" solution being to switch C2S to using full Update instead of partial Update. yes, this is a normative change; yes, it's backwards-incompatible; but it is functionally the desired behavior.

particularly, there are other considerations for why "c2s full Update" is desirable: parallelism between c2s and s2s. the outbox has "less work to do" because it doesn't need to modify the activity before further delivery. this is especially important in the case where signatures are client-side. a client can sign an Update activity with its client keys, and pass it along to the outbox which handles the side effects opaquely. then, the outbox delivers to the inboxes of the delivery targets, and those recipients can verify that the activity was not tampered with by any intermediate servers. (similar logic is also a pre-requisite condition for e2ee.)

it's frankly not clear what the intended handoff is between the "partial update" and the "full update":

Note that this behavior is for client to server interaction where the client is posting to the server only. Server to server interaction and updates from the server to the client should contain the entire new representation of the object, after the partial update application has been applied.

i don't know what "updates from the server to the client" means in this case. it implies that the client is an actor that has its own inbox! how else would the server send an Update to the client?

@steve-bate
Copy link

@steve-bate that's an interesting idea and i hadn't considered it. i guess we could say that the Update.object is in JSON Patch form?

It might work with the current definition if there was a special "null" value for deleting properties/triples (like @evanp mentioned). I haven't experimented with it enough to know. From a Linked Data perspective, I wouldn't want an @json-typed property (for the reason you mentioned) and JSON Patch and JSON Merge Patch (RFC 7386) are non-LD JSON (but maybe it's possible to define a JSON-LD context for them?).

Some LD-related references (just food for though):

@nightpool
Copy link
Collaborator

In the C2S partial update case, the object is the partial update description. However, AP C2S partial Updates (typically) use the target URI as the id of the update description, which makes no sense.

Okay, I see where you're coming from now, but I think you're substantially misunderstanding how the Update activity is designed and its semantics.

The ActivityPub spec does not (currently, extensions aside), have any concept of an "update description" or "patch object" like you claim. Instead, the idea is that you only serialize the properties that have changed, and this "partial serialization" is used by the backend server to update the object. This isn't saying that the object is a "edit description", but instead just a partial serialization of the full object (just like any JSON-LD document can be a partial serialization of any resource)

The idea was then to use null to represent properties that have been dropped. This is a very effective and simple way to process removed properties. However, this "partial serialization" needs to be handled prior to JSON-LD processing and conflicts with some of the JSON-LD algorithms. I think we can add a special "as:nil" ID to fix this without abandoning the "partial serialization" concept entirely.

@nightpool
Copy link
Collaborator

nightpool commented Nov 18, 2024

i don't know what "updates from the server to the client" means in this case. it implies that the client is an actor that has its own inbox! how else would the server send an Update to the client?

Presumably it means any Update activities shown in the actor's inbox or otherwise fetched by the client (e.g. by dereferencing the @id property of an Update activity)

@steve-bate
Copy link

I think you're substantially misunderstanding how the Update activity is designed and its semantics.

you only serialize the properties that have changed, and this "partial serialization" is used by the backend server to update the object

I'd claim this is the misunderstanding of the C2S partial update, but given the underspecification of the feature, it's debatable. In general, it's not a partial serialization. The support for "null"-valued properties are the hint. It's actually an edit/diff/patch specification. A property that already exists is an update/replace. A property that does exist is an add/insert. A property with a "null" is a delete. You can't just merge the properties in the edit description with the existing object. Given the S2S Update does use a serialized object for completely replacing the existing resource, I can understand how one might assume C2S is similar.

The spec uses the phrase:

the entire new representation of the object, after the partial update application has been applied

I'm claiming the "partial update application" (the object value) is the edit/patch/diff description that will be applied to the target resource. The id is intended to be the update target URI. This is more clearly described in the S2S Update description where it states "the receiving server SHOULD update its copy of the object of the same id to the copy supplied in the Update activity". That explicitly describes two different resources with the same id (the copy supplied by the Update and current resource). Even for S2S, this causes strange side effects in a Linked Data context.

An LD application would transform the Update JSON-LD to an RDF graph containing the activity and the embedded "copy" resource. It then adds an inbox reference to that activity URI. The update is applied as a side-effect. The inbox activity object now refers to the updated object (since it has the same URI as the "copy"). If the inbox subgraph is serialized to JSON-LD, the activity will have a different object (assuming it's embedded in the serialization) than the original Update. In fact, all previous Updates will now refer to the most recently update resource when the inbox subgraph is serialized. Even worse, the Create will also refer to it (but that's a different, although related, issue).

Even non-LD servers can have this problem (I've seen it). Mastodon doesn't have it because it has no stored inbox/outbox collections or stored activities.

@trwnh
Copy link
Author

trwnh commented Nov 19, 2024

I think we can add a special "as:nil" ID to fix this without abandoning the "partial serialization" concept entirely.

maybe, but i'm still seeing the other issues conceptually -- the lack of parallelism, and especially the lack of passthrough for client-generated activities, as well as the implications this has for client-side signing and for clean layering of protocols, separation of concerns, etc. as it stands, the expected behavior is to:

  1. have the client POST a C2S "partial Update" to the outbox endpoint
  2. the software running at that outbox endpoint applies the delta and modifies the resource
  3. the software running at that outbox generates a new "full Update" activity for S2S purposes etc?
  4. the software running at that outbox inserts that "full Update" into the outbox OrderedCollection, does inbox delivery against that "full Update", returns 201 Created with a Location pointing to that "full Update. the original C2S "partial update" is consumed/discarded.

this translation between "partial update" and "full update" still feels entirely unnecessary and more than a little weird, and "step 3" is entirely undescribed and unspecified. you just have to assume that the server will generate its own activity and send it on your behalf? in other words, there is a disconnect between C2S and S2S; the C2S role of outbox is to modify the resource, but the S2S role of outbox to deliver to inboxes found via to/cc/audience/bto/bcc. if the C2S activity is discarded and an entirely new S2S activity is generated, then the outbox is no longer "just" an outbox. it's basically a proxy actor, with its own logic and own behaviors.

i think the ideal is that the outbox SHOULD NOT modify client activities, or at least should modify them as little as possible. sadly, that's not the situation we're in. (we also have bto/bcc stripping, id generation, and possibly other places where activities get modified. some of these can be worked around, but "throw away the activity and generate a new one" is pretty hard to work around.) so it looks like we have to accept that the outbox is doing certain things (has certain behaviors) that are highly specific to it being an "activitypub server". which is regrettable if those behaviors are irreconcilable with other specs or other worldviews (as it similarly appears to enforce a worldview where the server is puppeting actors only somewhat according to the activities it receives at the outbox.)

i guess the bigger problem here is that these unstated assumptions and requirements should be stated and specified.

but focusing on just this issue, it looks like the issue is basically like so:

  1. we are stuck with c2s partial update for now
  2. partial update is not LD compliant
  3. partial update is going to be consumed/discarded by the server anyway, which (unstated, implicit requirement) generates a "full Update" for all other purposes (outbox collection insertion, inbox delivery, responding with 201 Created to the client POST request)

if we accept this much, then perhaps specifying an as:nil is workable. it sure isn't great, though!


one small footnote: @steve-bate would it be wrong to say that the POST to outbox is itself not really LD? which is to say, you are not actually POSTing a resource. the real resource is what the server generates. the POST body/payload is only the material you want to use to generate that resource on the server. this is inherent to the POSTed payload not having an id and therefore being an anonymous / blank node.

for example, some equivalent Turtle.

this is the prior object:

@prefix as: <https://www.w3.org/ns/activitystreams#> .

<https://server.example/note-1> a as:Note .
<https://server.example/note-1> as:content "I lik ice cream." .
<https://server.example/note-1> as:attributedTo <https://server.example/you> .
<https://server.example/note-1> as:summary "This will be removed later." .

then you POST a "partial update" to the server, which contains the material

@prefix as: <https://www.w3.org/ns/activitystreams#> .

# This is a blank node representing the delta material only.
# It is not the same as the final "full Update" activity.
_:b0 a as:Update .
_:b0 as:object <https://server.example/note-1> .

# We update the content and remove the summary.
<https://server.example/note-1> as:content "I like ice cream." .
<https://server.example/note-1> as:summary as:nil .

# We want to deliver the final "full Update" to addressees, not the "partial Update".
_:b0 as:to <https://server.example/your-followers> .

which gets applied as and translated into:

@prefix as: <https://www.w3.org/ns/activitystreams#> .

# The server assigned an id to the "full update", as well as potentially assigning an actor.
<https://server.example/the-id-assigned-to-the-full-update> a as:Update .
<https://server.example/the-id-assigned-to-the-full-update> as:actor <https://server.example/you> .
<https://server.example/the-id-assigned-to-the-full-update> as:object <https://server.example/note-1> .

# Insert all statements from the full representation of note-1 here, after applying the "partial update" _:b0.
<https://server.example/note-1> a as:Note .
<https://server.example/note-1> as:content "I like ice cream." .
<https://server.example/note-1> as:attributedTo <https://server.example/you> .

# The server will then deliver this "full Update" to the specified resources.
<https://server.example/the-id-assigned-to-the-full-update> as:to <https://server.example/your-followers> .

the behavior of the outbox would then be roughly described as the following:

  • Initialize graph g0 with statements from the body payload of the POST
  • If ?payload a as:Update, then query ?payload as:object ?object_to_edit and load the representation of ?object_to_edit as graph g1
  • From graph g0, find all statements of the form ?object_to_edit ?p ?o
    • For graph g1, remove all statements of the form ?object_to_edit ?p ?_
    • For graph g1, insert all statements we found from graph g0 regarding ?object_to_edit ?p ?o
    • For graph g1, remove all statements of the form ?object_to_edit ?p as:nil
  • Initialize graph g2 with a new subject whose IRI is assigned by the outbox server. Let's call this ?activity
    • For graph g2, insert statement ?activity as:actor ?actor where ?actor is obtained from graph g0 by ?_:b0 as:actor ?actor
    • For graph g2, insert statement ?activity a as:Update
    • For graph g2, insert statement ?activity as:object ?object_to_edit
    • For graph g2, insert all statements from graph g1 (representing ?object_to_edit)
  • Serialize and deliver graph g2 to delivery targets

basically we have to be careful because we can't just insert new statements, we also have to remove all old statements that have the same predicate. then we can follow up by removing all statements where the object is as:nil

example, if there are multiple statements of the form:

@prefix as: <https://www.w3.org/ns/activitystreams#> .

?s as:tag ?1
?s as:tag ?2
?s as:tag ?3

then a "partial Update" that includes as:tag in ANY one statement needs to remove ALL such statements from the object's representation.

@trwnh
Copy link
Author

trwnh commented Nov 19, 2024

ugh, one problem with as:nil i just realized: it still won't work cleanly with JSON-LD because of the @type: @id vs @type: @vocab split. So we can't define "nil": "as:nil" in the @context. this is basically the same as the "Public": "as:Public" problem. it would have to be ALWAYS expressed as as:nil in every case.

@trwnh
Copy link
Author

trwnh commented Nov 19, 2024

Actually I think a slightly cleaner way to do it is to explicitly define a property of @type: @vocab and call it something like "propertiesToRemoveWhenUpdating", then just put the properties you expect to remove from the final representation of the object.

I do also agree with @steve-bate that there should ultimately be a distinction between the patch/delta itself, vs. the object being updated. But for now, this kind of works?

{
  "id": "https://server.example/note-1",
  "type": Note",
  "content": "I lik ice cream."
  "summary": "This will be removed later",
  "https://ns.example/extension": true
}
{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    {
      "propertiesToRemoveWhenUpdating": {
        "@id": "https://w3id.org/fep/xxxx/propertiesToRemoveWhenUpdating",
        "@type": "@vocab",
        "@container": "@set"
      },
      "extension": "https://ns.example/extension"
    }
  ],
  "type": "Update",
  "object": {
    "id": "https://server.example/note-1",
    "content": "I like ice cream."
  },
  "propertiesToRemoveWhenUpdating": ["summary", "extension"]
}

The problem I intentionally left in here for illustrative purposes is that you might still need to do some level of LD processing.

Aside from that, it still seems conceptually very muddy that the object contains an id and then also separately contains properties to be overridden. It's a bit like saying "update the id to be the id."

That leaves the options as far as I can say:

  • Declare that the outbox doesn't do LD processing. (problematic for several reasons; doesn't work with extension properties at all)
  • Define a new PartialUpdate activity that takes instrument being some PartialUpdatePatchSet and applies it to object. (perhaps less problematic?)
  • Make a slightly backwards-incompatible change to add new processing requirements to C2S Update. (some new term would get defined, and the behavior would be changed.)
  • Make a backwards-incompatible change to say that C2S Update is actually a "full Update". (least problematic in concept, probably more likely to be problematic to anyone who implemented the current behavior of "partial Update")

@steve-bate
Copy link

one small footnote: @steve-bate would it be wrong to say that the POST to outbox is itself not really LD? which is to say, you are not actually POSTing a resource. the real resource is what the server generates. the POST body/payload is only the material you want to use to generate that resource on the server. this is inherent to the POSTed payload not having an id and therefore being an anonymous / blank node.

I think the conceptual model is not at all clear in the current spec, but I do think the C2S Update POST is LD. The POSTed resource is the C2S Activity/Object instruction (more on this later). Other resources will be generated by the server based on that resource. None of them are more or less "real" than the others, but they should have different identifiers (or be blank nodes).

The related topics are so tangled that it's difficult to discuss them clearly without pulling in tangential concepts. For example, outbox delivery is not specific to S2S although that's where it's described in the spec. Independent of federation, one would still expect outbox-triggered Activity delivery to actors in the same server. If you squint at the spec long enough, it seems this requirement is at least implied in Section 7.1 although it's in the "Server to Server Interactions" material. For this reason, I'm going to try to avoid using S2S qualifiers in this response.

I view the C2S partial Update as an instruction: "Update the specified resource based on the patch I'm providing." The Activity delivered by the outbox-triggered side effect is a notification: "This resource has been updated". The latter use of Update seems to be more consistent with the AS2 intent (note the past tense in the description).

AS2 Update description:

Indicates that the actor has updated the object. Note, however, that this vocabulary does not define a mechanism for describing the actual set of modifications made to object.

As I said earlier, I claim the C2S instruction and the subsequent notification are different resources. It seems to me that the C2S instruction is what should be in the outbox. In your example, that would be a "blank node" in an LD context if the Client doesn't assign an id. I think of the server's activity id as being for the notification, although the spec isn't explicit about that.

In this view, the outbox contains all objects posted by clients, but not all side effect activities that have been delivered to inboxes (hopefully that's clear). Although it's a bit vague, but the outbox-triggered delivery requirements only require the server to deliver something to the client-specified addresses when an object added to the outbox via C2S rather than the actual outbox object.

It would be possible to add a property that links the C2S instruction to the resource(s) created by server side effects. This would allow clients to discover the activities created from their instructions. The Location header might be able to partially serve this purpose for a specific POST but I think also having a persistent link would be better.

it still seems conceptually very muddy that the object contains an id

I agree, unless that id is the id of the patch rather than the target id.

It doesn't solve all of the numerous issues, but I still think an easy first step that solves some of them is the use the target property to specify the target URI of the C2S partial Update instruction. The object would typically be a blank node (although that's not absolutely necessary as long as the optional id is for the "patch" itself and not the target resource).

I think this makes the semantics of the partial update clearer.


Original issue that resulted in C2S partial Update changes to the spec: #85

What's meant by "server to client" interaction is unclear, as you mentioned. Is that for outbox serialization or S2C resource serialization in general (URI derferencing)? Were they expecting that the outbox serialization would embed the full updated object in the serialized Update activities (which means they'd be different from the original C2S instruction)? Or was it just not fully thought through?

@trwnh
Copy link
Author

trwnh commented Nov 20, 2024

I claim the C2S instruction and the subsequent notification are different resources

this is what i was trying to say i think. but still, you could say that "C2S partial update is not LD, process it as plain JSON therefore null can be used". it would be really bad for compatibility with other specs and ecosystems, but you could say it. i agree that the model is unclear though.

the outbox contains all objects posted by clients, but not all side effect activities that have been delivered to inboxes (hopefully that's clear)

it's clear i guess, but i either disagree or i desperately want it to not be true. the outbox either does or should contain activities produced by the actor, not raw payloads produced by a client. ideally these would be the same or very similar, but we are in a situation where the server will always mutate the payload, even if only to add an id. (or strip bto/bcc, or generate a "full Update" based on applying the "partial Update", or...)

at best, i think we can say there should be a property that points to the blank node / anonymous activity that was used to generate the final activity? the client signature, if any, can be preserved there. but i am also aware that this could significantly increase the size of the payload by perhaps 100% or more. something like this:

{
"id": "https://server.example/activity",
"clientProvidedPayload": {
  "actor": "https://server.example/actor",
  "type": "PartialUpdate",
  "object": "https://server.example/object",
  "instrument": {
    "type": "PatchSet",
    "upsert": {
      "content": "I like ice cream."
    },
    "remove": ["summary"]
  },
  "proof": {...}  // generated by client using client keys
},
"actor": "https://server.example/actor",
"type": "Update",
"object": {...},
"proof": {...}  // generated by server using actor/server keys
}

@evanp evanp changed the title Section 6.3.1 C2S Partial Update behavior is impossible and should be deprecated Section 6.3.1 C2S Partial Update property deletion behavior is impossible and should be deprecated Dec 27, 2024
@evanp
Copy link
Collaborator

evanp commented Dec 27, 2024

I've added an erratum with this text:

In Section 6.3.1 "Partial updates", the following sentence should be deleted: A special exception is for when the value is the json null type; this means that this field should be removed from the server's representation of the object.

@evanp evanp added Needs Group Input/Decision and removed Needs errata We need to add errata for this labels Dec 27, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs FEP Needs a FEP Needs Group Input/Decision Needs Primer Page Needs a page in the ActivityPub primer Next version Normative change, requires new version of spec
Projects
None yet
Development

No branches or pull requests

4 participants