-
Notifications
You must be signed in to change notification settings - Fork 78
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
Comments
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. |
I think we have four next steps.
|
This issue has been labelled as potentially needing a FEP, and contributors are welcome to submit a FEP on the topic. |
deprecating Update entirely feels like throwing the baby out with the
bathwater, considering that tons of deployed implementations use S2S
updates that do not have this "delete with null" behavior
I think adding an erratum deprecating the null behavior specifically is
good enough for now.
…On Fri, Nov 15, 2024, 9:28 AM github-actions[bot] ***@***.***> wrote:
This issue has been labelled as potentially needing a FEP, and
contributors are welcome to submit a FEP
<https://codeberg.org/fediverse/fep/src/branch/main#submitting-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.
—
Reply to this email directly, view it on GitHub
<#477 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABZCV7TKFRJ7736W5WRBLD2AYVKPAVCNFSM6AAAAABRB3W2XWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDINZZGUYTGNZSHE>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
The other significant issue with (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 Another possibility would be disallow the current style of update. If there were a predicate to indicate replacement (e.g., |
Can you give a more concrete explanation of why |
In the C2S partial update case, the 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 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 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"
} |
@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
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
so you could say something like
in which case, the C2S would need to be reworked to apply
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
and there is no syntactical difference between this and 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":
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? |
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 Some LD-related references (just food for though): |
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 |
Presumably it means any |
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:
I'm claiming the "partial update application" (the 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 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. |
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:
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 i think the ideal is that the 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:
if we accept this much, then perhaps specifying an 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:
then you POST a "partial update" to the server, which contains the material
which gets applied as and translated into:
the behavior of the
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 example, if there are multiple statements of the form:
then a "partial Update" that includes as:tag in ANY one statement needs to remove ALL such statements from the object's representation. |
ugh, one problem with as:nil i just realized: it still won't work cleanly with JSON-LD because of the |
Actually I think a slightly cleaner way to do it is to explicitly define a property of 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?
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 That leaves the options as far as I can say:
|
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:
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 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.
I agree, unless that 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 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? |
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.
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
} |
I've added an erratum with this text:
|
#396 was closed without resolution, so I'm reopening discussion of the unsolved issue.
ActivityPub:
@steve-bate:
@evanp:
@trwnh:
summary
The text was updated successfully, but these errors were encountered: