ucan-wg / invocation

UCAN Invocation & Pipelining
Other
12 stars 5 forks source link

Update Task field names #13

Closed expede closed 1 year ago

expede commented 1 year ago

Preview

Naming things is hard.

A few people have raised that on reads like an event handler 😅 The original intention for switching from with/do to on/call was that both with and do are keywords in common languages.

call seems basically fine, and in fact a lot of OO languages come with a .call method (e.g. in Ruby).

This PR proposes obj, short for "object", which I think is sufficiently general. The other option could be uri, but obj seems more in line with the "you're programming right now" mode of thought.

I also updated input to args, but am happy to revert that. It's one character shorter 🤷‍♀️

Changes

🦖 Prehistory

{
  "with": "https://example.com/blog/",
  "do": "crud/create",
  "input": {
    "title": "hello world",
    "status": "draft"
  } 
}

🏺 Before

{
  "on": "https://example.com/blog/",
  "call": "crud/create",
  "input": {
    "title": "hello world",
    "status": "draft"
  } 
}

🚀 After

{
  "obj": "https://example.com/blog/",
  "call": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

Alternatives

We've also talked about these:

Nested

{
  "https://example.com/blog/": {
    "crud/create": {
      "title": "hello world",
      "status": "draft"
    }
  } 
}

or

{
  "obj": "https://example.com/blog/"
  "call": {
    "crud/create": {
      "title": "hello world",
      "status": "draft"
    }
  } 
}

These look closer to UCAN 0.10.x, but open up more schema errors. For exmaple, it is not a syntactic violation — but is a semantic violation — to do this:

{
  "https://example.com/blog/": {
    "crud/create": {
      "title": "hello world",
      "status": "draft"
    },
    "crud/update": {
      "title": "something else",
      "status": "published"
    }
  } 
}

Tuple

(Just skip the labels)

[
  "https://example.com/blog/",
  "crud/create", 
  {
    "title": "hello world",
    "status": "draft"
  } 
]

... or written to look kind of vaguely Lispy 😆

["https://example.com/blog/", "crud/create", 
  {"title": "hello world","status": "draft"}
]
expede commented 1 year ago

We could also give up on having them read cleanly in natural langauge (which is more like really old UCANs):

{
  "rsc": "https://example.com/blog/", // Resource
  "call": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

or

{
  "uri": "https://example.com/blog/",
  "call": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

I don't love uri because that's the syntax, not its role.

I asked ChatGPT, and an interesting option it (eventually) suggested was:

{
  "using": "https://example.com/blog/",
  "perform": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

Which is actually kind of nice IMO. It could be shortened to:

{
  "usg": "https://example.com/blog/",
  "prfm": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

...or just...

{
  "using": "https://example.com/blog/",
  "call": "crud/create",
  "args": {
    "title": "hello world",
    "status": "draft"
  } 
}

ChatGPT tells me that using is a keyword in C, C++, and C#. Arguably we should thus avoid it, but I also think it reads very well in C you're definitely not directy accessing the fields 😉

I made a branch for that here just in case https://github.com/ucan-wg/invocation/blob/alt/README.md

Gozala commented 1 year ago

@expede during the happy hour at IPVM Wrokshop we have also talked about idea of surfacing properties of the operation, I don't exactly remember axis you've listed but I think there was

And in than conversation we have entertained idea of having different verbs to signify that, from my recollection it was

If that is still desired it might be worth considering as an alternative to call field.

Gozala commented 1 year ago

@expede @zeeshanlakhani I'm also getting more inclined to following structure instead:

{
   "crud/create": {
        "https://example.com/blog/": {
           "title": "hello world",
           "status": "draft"
        } 
   }
}

Which aligns with this statement in the spec

The do field is critical in understanding what kind of action will be performed and CAN NOT be substituted with Await.

And also happens to match the way we do the pattern matching as we route by the ability.

Also if we do ☝️ I'd be inclined to dropping nnc in favor of _ field in the input so we won't have to warp that structure any further.

zeeshanlakhani commented 1 year ago

@expede during the happy hour at IPVM Wrokshop we have also talked about idea of surfacing properties of the operation, I don't exactly remember axis you've listed but I think there was

  • Idempotence
  • mutability
  • query

And in than conversation we have entertained idea of having different verbs to signify that, from my recollection it was

  • post - mutates and isn't idempotent
  • put / delete - mutates but is idempotent
  • get / select / query - pure computation

If that is still desired it might be worth considering as an alternative to call field.

Yeah, we were talking about these properties at a different level and spec, right @expede? Part of the task definition/type itself vs at the task invocation? Even though we know what put properties are, there are other non-HTTP semantic concepts/terms that can be pure or impure, or mutate or not.

zeeshanlakhani commented 1 year ago

@expede @zeeshanlakhani I'm also getting more inclined to following structure instead:

{
   "crud/create": {
        "https://example.com/blog/": {
           "title": "hello world",
           "status": "draft"
        } 
   }
}

Which aligns with this statement in the spec

The do field is critical in understanding what kind of action will be performed and CAN NOT be substituted with Await.

And also happens to match the way we do the pattern matching as we route by the ability.

Also if we do ☝️ I'd be inclined to dropping nnc in favor of _ field in the input so we won't have to warp that structure any further.

Personally, I prefer semantic, typed schema definitions (closer to protos) instead of this. A _ field just has no semantic meaning, but a nonce, nnc, does right?

expede commented 1 year ago

@expede during the happy hour at IPVM Wrokshop we have also talked about idea of surfacing properties of the operation, I don't exactly remember axis you've listed but I think there was

* Idempotence

* mutability

* query

And in than conversation we have entertained idea of having different verbs to signify that, from my recollection it was

* post - mutates and isn't idempotent

* put / delete - mutates but is idempotent

* get / select / query - pure computation

If that is still desired it might be worth considering as an alternative to call field.

[...]

Yeah, we were talking about these properties at a different level and spec, right @expede? Part of the task definition/type itself vs at the task invocation? Even though we know what put properties are, there are other non-HTTP semantic concepts/terms that can be pure or impure, or mutate or not.

Yeah I remember this conversation! It's a clever idea, but I think it doesn't actually work in the IPVM context unfortunately 👇

What Are The Properties?

The properties were:

We've tried to simplify this down a few times, but AFAICT right now this is the minimal set, and you can have up to 2 at any time. Here's a screenshot of a table that I threw together a couple weeks back as part of an internal discussion where we attempt to create a safety heirarchy:

image

It turns out that it's less of a straight heirarchy and more of a partial order. There's more states than HTTP verbs unfortunately, mostly thanks to their being idempotent queries (GET is not idempotent) and pure functions.

Where This Info Lives

The idea is that these properties would live in each Task definition rather than per invocation. People writing invocations wouldn't need to reason about this info. We only need these props for the runtime to know how which steps in a workflow require special handling. For example, I know that I need exact-once semantics for sending an email, so I can't fan that out and race the processes and compare recipts for verification. I can do that for an HTTP PUT or Wasm execution, though!

We need to know what kind of function to run, which is defined by the pair (uri, action). For example, if I have a data: or ipfs: URI, it could be a Docker container, a Wasm module, or an image (or any other kind of binary). I need to know what kind of action to perform on that. The same goes for the ability field on a well-known URI type (there's many ways to crud/create depending on the specific URI).

In general, IPVM is going to treat every task as maximally dangerous, unless our backend handler can tell us "this one is (e.g.) not at mutation & is idempotent", which lets us be way more liberal with how we run it.

expede commented 1 year ago

A _ field just has no semantic meaning, but a nonce, nnc, does right?

Yeah agreed on nnc vs _ 👍 I think I understand the rationale for _, but also the two extra chars make the intent clearer.

Personally, I prefer semantic, typed schema definitions (closer to protos) instead of this

I definitely see both sides of this, especially with UCAN 0.10 moving the direction it's going. Also getting rid of field names sidesteps the issue of naming all together.

That said, I really don't love all of the edge cases it opens up. Arguably using the quasi-Lisp array syntax gets around that, but now we're in unnamed ordered args territory, which is generally advised against.

I don't have super strong feelings on this one, but most people that I've asked about this one have had a gut reaction to use named fields.

Gozala commented 1 year ago

Few ideas what we can rename call into:

expede commented 1 year ago

Thanks @zeeshanlakhani! Fixed in #15