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

fix: Improve offer documentation #876

Merged
merged 26 commits into from
Dec 3, 2023

Conversation

gibson042
Copy link
Member

...particularly to document offerArgs.

Copy link

cloudflare-workers-and-pages bot commented Nov 21, 2023

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: c53f09e
Status: ✅  Deploy successful!
Preview URL: https://4be18072.documentation-7tp.pages.dev
Branch Preview URL: https://gibson-2023-11-improve-offer.documentation-7tp.pages.dev

View logs

@gibson042 gibson042 force-pushed the gibson-2023-11-improve-offer-documentation branch from 82dd218 to a689047 Compare November 21, 2023 00:38
Copy link

@FUDCo FUDCo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple of minor nits, but this seems like a strict improvement.

Comment on lines 425 to 429
Passables include pass-by-copy primitive values such as numbers and strings and
pass-by-reference values such as Remotables and Promises.
Passables also include hardened acyclic pass-by-copy containers that recursively terminate
in non-container passables, such as CopyArrays like `harden(['foo', 'bar'])` and
CopyRecords like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth a mention in passing of some things that aren't passable, just to underscore that it's a meaningful concept.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, but if so, let's put that in the Marshaling section.

I'd rather not have any novel info in the glossary. I'd like it to be more of an index. Each item should have a brief gloss plus a link to where the term is defined in context.

main/glossary/README.md Show resolved Hide resolved
Copy link
Collaborator

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! Lots of helpful changes here. I have a few suggestions, but mostly this is very good as it stands.

I'll bring up a local copy and verify links and visual formatting before approving.

main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe-data-types.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe-data-types.md Outdated Show resolved Hide resolved
(For more detail, see [Why do Zoe keywords have to start with a capital letter? #8241](https://github.com/Agoric/agoric-sdk/discussions/8241).)
`NaN` and `Infinity` are also not allowed as keywords.

<a name="amountkeywordrecord"></a>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't that HTML tag have to surround something to have an effect? https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a says to use id instead.

stackoverflow thinks it's not okay for it to be empty.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve found that this works, but the browser is not obliged to scroll farther than necessary to put the top of this marker above the fold. Capturing content obliges the browser to scroll to show as much of the content as fits.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

id is definitely the correct attribute (my muscle memory here is very old and outdated), but inner content is not necessary to establish what I know of as an "anchor link". This particular technique of using an empty a element before a Markdown section heading allows external links using an old target to still land in approximately the right place without suffering automatic slug generation issues that cause otherwise preferable Markdown like ## KeywordRecord <a id="amountkeywordrecord"></a> to render incorrectly in many implementations, e.g.:

--- expected
+++ actual
-<h2 id="keywordrecord">KeywordRecord <a id="amountkeywordrecord"></a></h2>
+<h2 id="keywordrecord-a-id-amountkeywordrecord">KeywordRecord <a id="amountkeywordrecord"></a></h2>

Comment on lines 302 to 303
respectively expressing conditions regarding what assets will be given, what must be
received in exchange, and an exit rule defining how/when the offer can be canceled.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... what is being given, what must be received to satisfy offer safety, and an exit rule ...

I'd say "is being given" because zoe requires that the proposal match the payments, and the contract won't see the offer if they don't match. (and the invitation will be burned.

"what must be received to satisfy offer safety" because the user can want any arbitrary thing (subject to want patterns provided by the contract), and it's a valid offer. If the contract doesn't match the want, then the offer gets its give back.

Is there a reasonable place to describe want patterns? Do we talk about makeInvitation from the contract author's perspective?

Copy link
Member Author

@gibson042 gibson042 Nov 29, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... what is being given, what must be received to satisfy offer safety, and an exit rule ...

I'd say "is being given" because zoe requires that the proposal match the payments, and the contract won't see the offer if they don't match. (and the invitation will be burned.

"what must be received to satisfy offer safety" because the user can want any arbitrary thing (subject to want patterns provided by the contract), and it's a valid offer. If the contract doesn't match the want, then the offer gets its give back.

Done.

Is there a reasonable place to describe want patterns?

I'll defer on this question, although Zoe Data Types and The Structure of Offers seem like reasonable locations for followup.

Do we talk about makeInvitation from the contract author's perspective?

It's mentioned at ZCF documentation and Writing and Installing a Contract, but they could go further.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not yet support want patterns. Looking forward to it though!

main/reference/zoe-api/zoe.md Outdated Show resolved Hide resolved
Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The keyword record stuff doesn't look right.

Comment on lines -162 to +177
An [invitation](#invitation) optionally returned by [`startInstance()`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISTR some discussion of deprecating / removing creator invitation in the name of zoe durability.
@Chris-Hibbert @erights what became of that?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a hope, with no concrete plan behind it. Not worth covering in the docs at this point.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be worth noting that startInstance is subsumed into startUpgradable. (It is, right?)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be worth noting that startInstance is subsumed into startUpgradable. (It is, right?)

That doesn't sound familiar. I think you're misremembering something, though I don't know what.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dug into this. The Agoric chain home object can provide startUpgradable as a thin wrapper for E(zoe).startInstance. It’s provided by vats/src/core/basic-behaviors.js. This is why we were unable to find startInstance in the core proposal in the dapp-game-places template during the hackathon. We eventually found startUpgradable and from there were able to figure out how to thread offerArgs thru the level of indirection.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startUpgradable is a power from the bootstrap environment; it's available to core-evals, but it's not part of the Zoe API.

The purpose of startUpgradable is somewhat relevant, though: it's to make sure we don't lose admin facets needed for upgrade.

Do we tell folks in the Zoe docs that startInstance() also returns an admin facet, and if you lose it, you will NEVER BE ABLE TO UPGRADE?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

startUpgradable should be covered in docs for bootstrap powers. Those are pretty thin. That's probably worth a separate issue...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISTR some discussion of deprecating / removing creator invitation in the name of zoe durability.
@Chris-Hibbert @erights what became of that?

It's a hope, with no concrete plan behind it. Not worth covering in the docs at this point.

I think we should explicitly state that it is deprecated. Whether we will ever be able to remove it remains to be seen, but I'm hopeful.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked for a relevant issue and found:

But it's one of those "do X" issues that doesn't say why do X... other than

That functionality can be supplied from the creatorFacet.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for finding that. In light of @samsiegart 's two comments at Agoric/agoric-sdk#5775 (comment) , I withdraw the request to emphasize the deprecation of creator invitation until Sam's question is resolved.

main/glossary/README.md Outdated Show resolved Hide resolved
Comment on lines 425 to 429
Passables include pass-by-copy primitive values such as numbers and strings and
pass-by-reference values such as Remotables and Promises.
Passables also include hardened acyclic pass-by-copy containers that recursively terminate
in non-container passables, such as CopyArrays like `harden(['foo', 'bar'])` and
CopyRecords like `harden({ keys: [0, 1], values: ['foo', 'bar'] })`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps, but if so, let's put that in the Marshaling section.

I'd rather not have any novel info in the glossary. I'd like it to be more of an index. Each item should have a brief gloss plus a link to where the term is defined in context.

main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
## Offer Arguments

To pass additional arguments to the **offerHandler** contract code associated with the
invitation, send them in an **offerArgs** record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it reasonable to assume that our audience is familiar with the use of "record" to mean "object"?

When we talk about things like a keyword record or an issuer record, there's more context. But here, there is precious little.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought that was official JavaScript terminology.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @erights coined record and in his interpretation, record means const-object-as-struct. The TC-39 Records and Tuples proposal uses the word to mean new-primitive-as-immutable-struct. TypeScript’s Record type suggests object-as-mutable-dictionary. I believe offerArgs is a const-object-as-dictionary. I am distinguishing “const” from “hardened” to mean: the informal contract is that this method will not mutate it and it consequently may be hardened.

It might be best to just say Object here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gibson042 This is great. We saw places where offerArgs was typed unknown and others where it was typed Object. I think we need to also converge on the latter in the code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

To pass additional arguments to the offerHandler contract code associated with the
invitation, send them in an offerArgs CopyRecord.

main/reference/zoe-api/zoe-data-types.md Outdated Show resolved Hide resolved
## KeywordRecord

A **KeywordRecord** is a [CopyRecord](/glossary/#passable) in which every property name
is a **[Keyword](#keyword)**, such as `harden({ Currency: quatloosBrand, CurrencyUnit: 100n })`.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That example seems weird. I don't believe anything in our Record<Keyword, Brand | bigint>. Did you mean to exhibit a Record<Keyword, Amount<'nat'>>? aka a Record<Keyword, { brand: Brand<'nat'>, value: NatValue }>

I wonder if it's useful to generalize to KeywordRecord at all. If so, we might as well lean into TypeScript notation: Record<Keyword, T>

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That example seems weird. I don't believe anything in our Record<Keyword, Brand | bigint>. Did you mean to exhibit a Record<Keyword, Amount<'nat'>>? aka a Record<Keyword, { brand: Brand<'nat'>, value: NatValue }>

No, for that first example I specifically wanted a KeywordRecord that had heterogeneous value types and so was not an AmountKeywordRecord/PaymentKeywordRecord/etc. But if you think this one is confusing, perhaps it could drift even further away from our flavor of DeFi?

Suggested change
is a **[Keyword](#keyword)**, such as `harden({ Currency: quatloosBrand, CurrencyUnit: 100n })`.
is a **[Keyword](#keyword)**, such as `harden({ Remotable: myMap, SupportedMethods: ['delete', 'get', 'has', 'set'] })`.

I wonder if it's useful to generalize to KeywordRecord at all. If so, we might as well lean into TypeScript notation: Record<Keyword, T>

I thought about that and actually started with something similar, but ultimately decided not to because a) the site already uses AmountKeywordRecord and PaymentKeywordRecord, and b) we don't explain use of TypeScript syntax and AFAICT don't expect developers to know it. But a thought did occur to me in typing the last response—what would you think about using it to help explain the concept for people who are familiar with it?

KeywordRecord

A KeywordRecord is a CopyRecord in which every property name
is a Keyword, such as harden({ Currency: quatloosBrand, CurrencyUnit: 100n }).
Subtypes further constrain property values (for example, an
AmountKeywordRecord is a KeywordRecord<Amount> in which every value is an
Amount and a
PaymentKeywordRecord is a KeywordRecord<Payment> in which every value is a
Payment).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... for that first example I specifically wanted a KeywordRecord that had heterogeneous value types ...

Such an example is a distraction, no? There is no such data type in the Zoe API.

This is the core of my request for changes.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. There are no KeywordRecords with heterogeneous value types, and I don't think we're likely to add them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, updated.

A KeywordRecord is a CopyRecord in which every property name
is a Keyword, such as harden({ Asset: moolaIssuer, Bid: simoleanIssuer }).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

KeywordRecord that had heterogeneous value types

Please don't. None of our keyword records are heterogeneous, and likely none ever will be, since the point of keywords as names is to support lookup by [] user-defined names, and therefore computed property names.

Comment on lines 289 to 293
## E(Zoe).offer(invitation, proposal?, paymentKeywordRecord?, offerArgs?)
- **invitation**: **[Invitation](./zoe-data-types.md#invitation) | Promise&lt;[Invitation](./zoe-data-types.md#invitation)>**
- **proposal**: **[Proposal](/glossary/#proposal)** - Optional.
- **paymentKeywordRecord**: **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)** - Optional.
- **offerArgs**: **[CopyRecord](/glossary/#passable)** - Optional.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: not having these kept in sync with agoric-sdk by machine is just maddening.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: not having these kept in sync with agoric-sdk by machine is just maddening

Indeed!

main/reference/zoe-api/zoe.md Outdated Show resolved Hide resolved

### OfferArgs
**paymentKeywordRecord** must be either `undefined` or a **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)**
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**paymentKeywordRecord** must be either `undefined` or a **[PaymentKeywordRecord](./zoe-data-types.md#keywordrecord)**
**paymentKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)**

https://github.com/Agoric/agoric-sdk/blob/0160e2fcb277340db2e3d25fca4c79af59b7e87c/packages/zoe/src/zoeService/types.js#L154

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like you're right. I consider the typeGuards definitive. Thanks for the correction.

Copy link
Member

@kriskowal kriskowal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, suggestions only.

Comment on lines -162 to +177
An [invitation](#invitation) optionally returned by [`startInstance()`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might also be worth noting that startInstance is subsumed into startUpgradable. (It is, right?)

main/glossary/README.md Outdated Show resolved Hide resolved
A *passable* is something that can be marshalled (see the
[Marshaling section in the JavaScript Distributed Programming Guide](/guides/js-programming/far.md#marshaling-by-copy-or-by-presence))
and sent to and from remote objects.
A *passable* is something that can be sent to and from remote objects.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
A *passable* is something that can be sent to and from remote objects.
A *passable* value is a JavaScript value that can be sent to and from remote objects.

main/glossary/README.md Outdated Show resolved Hide resolved
## Offer Arguments

To pass additional arguments to the **offerHandler** contract code associated with the
invitation, send them in an **offerArgs** record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe @erights coined record and in his interpretation, record means const-object-as-struct. The TC-39 Records and Tuples proposal uses the word to mean new-primitive-as-immutable-struct. TypeScript’s Record type suggests object-as-mutable-dictionary. I believe offerArgs is a const-object-as-dictionary. I am distinguishing “const” from “hardened” to mean: the informal contract is that this method will not mutate it and it consequently may be hardened.

It might be best to just say Object here.

## Offer Arguments

To pass additional arguments to the **offerHandler** contract code associated with the
invitation, send them in an **offerArgs** record.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@gibson042 This is great. We saw places where offerArgs was typed unknown and others where it was typed Object. I think we need to also converge on the latter in the code.

(For more detail, see [Why do Zoe keywords have to start with a capital letter? #8241](https://github.com/Agoric/agoric-sdk/discussions/8241).)
`NaN` and `Infinity` are also not allowed as keywords.

<a name="amountkeywordrecord"></a>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ve found that this works, but the browser is not obliged to scroll farther than necessary to put the top of this marker above the fold. Capturing content obliges the browser to scroll to show as much of the content as fits.

main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe-data-types.md Outdated Show resolved Hide resolved
Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyword stuff is addressed to my satisfaction

Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just comments so far, only on the README

Comment on lines -162 to +177
An [invitation](#invitation) optionally returned by [`startInstance()`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
An [invitation](#invitation) optionally returned by [`E(zoe).startInstance(...)`](/reference/zoe-api/zoe.md#e-zoe-startinstance-installation-issuerkeywordrecord-terms-privateargs) that the contract instance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ISTR some discussion of deprecating / removing creator invitation in the name of zoe durability.
@Chris-Hibbert @erights what became of that?

It's a hope, with no concrete plan behind it. Not worth covering in the docs at this point.

I think we should explicitly state that it is deprecated. Whether we will ever be able to remove it remains to be seen, but I'm hopeful.

main/glossary/README.md Show resolved Hide resolved
main/glossary/README.md Show resolved Hide resolved
main/glossary/README.md Show resolved Hide resolved
@@ -288,7 +301,7 @@ is available [here](https://www.computerweekly.com/blog/Open-Source-Insider/What
A [payment](#payment) whose amount represents (and is required for) participation in a contract instance.
Contracts often return a creator invitation on their instantiation, in case the contract instantiator wants
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, I think we should deemphasize and deprecate creator invitations.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise withdrawn until Sam's question is resolved.

main/glossary/README.md Show resolved Hide resolved
main/glossary/README.md Outdated Show resolved Hide resolved
main/glossary/README.md Show resolved Hide resolved
(see [Exit Rule](#exit-rule) for details on the last). For example:
Proposals are records with `give`, `want`, and/or `exit` properties respectively
expressing [offer](#offer) conditions regarding what assets will be given,
what must be received in exchange to satisfy offer safety, and
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possible misunderstanding that offer safety means you'll get what you said you want. At least make "offer safety" and explicit link to that glossary entry. Avoiding the possible misunderstanding would be even better.

main/glossary/README.md Outdated Show resolved Hide resolved
@erights erights self-requested a review November 30, 2023 01:25
Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more. But I clearly won't finish tonight.

Btw, I am not trying to check or follow any links, as I cannot do so simply in the markdown preview mode.

main/guides/getting-started/contract-rpc.md Outdated Show resolved Hide resolved
@@ -112,7 +112,7 @@ The [vstorage-viewer](https://github.com/p2p-org/p2p-agoric-vstorage-viewer) con
## Specifying Offers

Recall that for an agent within the JavaScript VM,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's an agent? Can we avoid this terminology completely please?

Sigh. To get rid of "agent" you'd also need to fix the diagram.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That diagram is nice!

main/guides/js-programming/far.md Outdated Show resolved Hide resolved
main/guides/js-programming/far.md Show resolved Hide resolved
main/guides/js-programming/far.md Show resolved Hide resolved

- `farName` `{ String }`
- `object-with-methods` `{ Object }` `[remotable={}]`
- `objectWithMethods` `{ Object }` `[remotable={}]`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worse here. Is the parameter name objectWithMethods or remotable?

Probably worth emphasizing that the objectsWithMethods MUST not be hardened or even frozen at the time of the Far call.

@erights erights self-requested a review November 30, 2023 02:03
Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some more. not done yet.

main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
main/reference/zoe-api/user-seat.md Outdated Show resolved Hide resolved
@@ -13,7 +13,7 @@ Returns an **IssuerRecord** containing the **[Issuer](/reference/ertp-api/issuer
**[Brand](/reference/ertp-api/brand.md)** associated with the **zcfMint**.

## aZCFMint.mintGains(gains, zcfSeat?)
- **gains**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)**
- **gains**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)**
- **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional.
- Returns: **ZCFSeat**

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below

The *gains*' **[Keywords](./zoe-data-types.md#keyword)** are in that **seat**'s namespace.

What does this mean?

Copy link
Member Author

@gibson042 gibson042 Nov 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think your guess is as good as mine... maybe referring to use of Keywords defined by the contract?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That seems like a good interpretation, but we don't refer to keywords as a namespace anywhere else, so better to recast this in more familiar terminology.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My best-effort rewording:

aZCFMint.mintGains(gains, zcfSeat?)

All amounts in gains must be of this ZCFMint's Brand
and the gains' Keywords should be defined by the contract instance in which zcfSeat is participating.
If zcfSeat is not provided, a new seat is used.
Mints the gains Amount of assets and adds them to zcfSeat's Allocation, then returns zcfSeat.

aZCFMint.burnLosses(losses, zcfSeat)

All amounts in losses must be of this ZCFMint's Brand
and the losses' Keywords must be defined by the contract instance in which zcfSeat is participating.
Subtracts losses from zcfSeat's Allocation, then
burns that amount of assets from the pooled Purse.

main/reference/zoe-api/zcfmint.md Outdated Show resolved Hide resolved
@@ -24,7 +24,7 @@ that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**. If a **seat**
it is returned. Otherwise a new **seat** is returned.

## aZCFMint.burnLosses(losses, zcfSeat?)
- **losses**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)**
- **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)**
- **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional.
- Returns: None

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below

then burn that amount of assets from the pooled Purse.

This is true and important. But would a reader have any idea what this pooled Purse is?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing then burns that amount of assets from the pooled Purse. to

then burns that amount of assets from the amount escrowed by Zoe for this contract instance.

main/reference/zoe-api/zoe-contract-facet.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe-contract-facet.md Outdated Show resolved Hide resolved
@@ -235,7 +236,7 @@ zcf.assertUniqueKeyword(keyword);
- Returns: None.

Prohibit invocation of invitatations whose description include any of the strings.
Any of the strings that end with a colon (:) will be treated as a prefix,
Any of the strings that end with a colon (`:`) will be treated as a prefix,
and invitations whose description string begins with the string (including the colon)
will be burned and not processed if passed to **E(Zoe).offer()**.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Chris-Hibbert , are they actually burned? That surprises me.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your instincts are correct. If the invitation is blocked, we Fail out of the offer() call and don't get to the immediately following burnInvitation().

    !instanceAdmin.isBlocked(description) ||
      Fail`not accepting offer with description ${q(description)}`;
    const { invitationHandle } = await burnInvitation(
      invitationIssuer,
      invitation,
    );

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change "will be burned and not processed if passed to E(Zoe).offer()" to "will not be processed if passed to E(Zoe).offer(). Instead, an exception will be thrown.".

Copy link
Collaborator

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Btw, I am not trying to check or follow any links, as I cannot do so simply in the markdown preview mode.

I am planning to pull down the whole PR and do the local build and review for link consistency, but I'm waiting for the changes to settle down.

main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
main/reference/zoe-api/user-seat.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zcfmint.md Outdated Show resolved Hide resolved
main/glossary/README.md Show resolved Hide resolved
@@ -288,7 +301,7 @@ is available [here](https://www.computerweekly.com/blog/Open-Source-Insider/What
A [payment](#payment) whose amount represents (and is required for) participation in a contract instance.
Contracts often return a creator invitation on their instantiation, in case the contract instantiator wants
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise withdrawn until Sam's question is resolved.

main/glossary/README.md Show resolved Hide resolved
main/guides/js-programming/far.md Show resolved Hide resolved
main/guides/js-programming/far.md Show resolved Hide resolved
- Pass-by-reference **_Remotables_**: objects that can be shared with remote systems which can then
invoke methods using e.g. `E()` eventual send notation. Remotables are created by [`Far()`](#far-api)
and related functions.
- Pass-by-reference **Promises** for Passables.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about Errors?

main/guides/js-programming/far.md Outdated Show resolved Hide resolved
@erights erights self-requested a review November 30, 2023 19:15

Users submit their **payments** and receive their **payouts** as **KeywordRecords**:
```js
quatloosPurse.deposit(payouts.Asset);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since payouts.Asset may be a promise for a payment, and since purse.deposit demands a non-promise for its payment argument, this example is incorrect or at best misleading.

main/reference/zoe-api/zoe-data-types.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe-data-types.md Show resolved Hide resolved
@erights erights self-requested a review November 30, 2023 21:07
Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This review pass complete. Over to you ;)

main/guides/zoe/proposal.md Show resolved Hide resolved
main/guides/zoe/proposal.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe.md Outdated Show resolved Hide resolved
main/reference/zoe-api/zoe.md Outdated Show resolved Hide resolved
@gibson042
Copy link
Member Author

Thanks for the astonishingly thorough review, @erights! I believe I've addressed all feedback.

Copy link
Collaborator

@Chris-Hibbert Chris-Hibbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extremely close. A few last-second nits.

`Invitations` are a special case of ERTP `payments`. They are linked to a specific contract `instance`, and
having one gives you the right to participate in that contract `instance`, for example, by making offers in it.
An [Invitation](/reference/zoe-api/zoe-data-types.md#invitation) is a special case of ERTP [Payment](/reference/ertp-api/payment.md). Each is linked to a specific contract [Instance](/reference/zoe-api/zoe-data-types.md#instance), and
having one gives you the right to participate in that contract instance by making offers with it.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep reading this and trying to re-word to "by making offers to it". But I think the it in "with it" is the invitation and the it in "to it" is the contract. Would you mind rewording? Perhaps "by using the invitation as the first argument to zoe.offer()".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those pronouns. Dereference them!

@@ -24,7 +24,7 @@ that **seat**'s **[Allocation](./zoe-data-types.md#allocation)**. If a **seat**
it is returned. Otherwise a new **seat** is returned.

## aZCFMint.burnLosses(losses, zcfSeat?)
- **losses**: **[AmountKeywordRecord](./zoe-data-types.md#amountkeywordrecord)**
- **losses**: **[AmountKeywordRecord](./zoe-data-types.md#keywordrecord)**
- **zcfSeat**: **[ZCFSeat](./zcfseat.md)** - Optional.
- Returns: None

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing then burns that amount of assets from the pooled Purse. to

then burns that amount of assets from the amount escrowed by Zoe for this contract instance.

Comment on lines 92 to 97
**description** is a required string describing the **Invitation**,
and should include whatever information is needed for a potential recipient of the **Invitation**
to know what they are getting in the optional *customProperties* argument, which is
put in the **Invitation**'s **value**.
to know what they are getting in the optional **customProperties** argument, which is
put in the **Invitation**'s **amount**.
Each one should be a string literal that is unique within its contract and
used only as the argument to make invitations of a particular kind.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops! customProperties should be customDetails. (Please fix above) The description here is garbled.

Suggested change
**description** is a required string describing the **Invitation**,
and should include whatever information is needed for a potential recipient of the **Invitation**
to know what they are getting in the optional *customProperties* argument, which is
put in the **Invitation**'s **value**.
to know what they are getting in the optional **customProperties** argument, which is
put in the **Invitation**'s **amount**.
Each one should be a string literal that is unique within its contract and
used only as the argument to make invitations of a particular kind.
**description** is a required string describing the role of this **Invitation**,
and should include whatever information is needed for a potential recipient of the **Invitation** to distinguish amoung this contract's invitations. Each description
should be a string literal that is unique within its contract.
The (optional) **customDetails** argument is included in the **Invitation**'s
**amount** and not otherwise relied on by Zoe.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that proposalShape lacks a description; would you care to suggest some text for it as well?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, man, that is not a small topic, and I don't see it touched on anywhere in these docs. The only reference material for it that I can find is in endo, and it is far from adequate as developer documentation.

I would say "a Pattern[ref] describing the required and allowed components of the proposal. Proposals that don't match the pattern will be rejected by Zoe without interacting with the contract." I won't claim that's adequate, but to say any more would take a week.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think you need to explicitly say that they are unique to a static call site within this contract. Or better, within this contract's source text. Otherwise, someone might misread to think they need to be unique per dynamic call to makeInstance.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@erights's comment applies to the description

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Only the description string. Thx.

@@ -235,7 +236,7 @@ zcf.assertUniqueKeyword(keyword);
- Returns: None.

Prohibit invocation of invitatations whose description include any of the strings.
Any of the strings that end with a colon (:) will be treated as a prefix,
Any of the strings that end with a colon (`:`) will be treated as a prefix,
and invitations whose description string begins with the string (including the colon)
will be burned and not processed if passed to **E(Zoe).offer()**.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please change "will be burned and not processed if passed to E(Zoe).offer()" to "will not be processed if passed to E(Zoe).offer(). Instead, an exception will be thrown.".

Comment on lines 43 to 44
The **InvitationIssuer** is a special type of **[Issuer](/reference/ertp-api/issuer.md)**.
Zoe has a single **InvitationIssuer** for its entire lifetime. All **Invitations** come from the
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's a different type of issuer. How about

Suggested change
The **InvitationIssuer** is a special type of **[Issuer](/reference/ertp-api/issuer.md)**.
Zoe has a single **InvitationIssuer** for its entire lifetime. All **Invitations** come from the
The **InvitationIssuer** is an **[Issuer](/reference/ertp-api/issuer.md)** that plays a
special role throughout Zoe. Zoe has a single **InvitationIssuer** for its entire
lifetime. All **Invitations** come from the **[Mint](/reference/ertp-api/mint.md)**
associated with the Zoe instance's **InvitationIssuer**.
The issuer is publicly available (via `E(Zoe).getInvitationIssuer()`), so the ability
to validate invitations is widely available.

Some example timers use Unix epoch time, while others count block height.
**proposal** must be either `undefined` or a record with **give**, **want**, and/or **exit** properties
respectively expressing conditions regarding what is being given,
what is expected in exchange (protected by offer safety), and
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
what is expected in exchange (protected by offer safety), and
what is desired in exchange (protected by offer safety), and

### OfferArgs
**paymentPKeywordRecord** must be either `undefined` or a **[PaymentPKeywordRecord](./zoe-data-types.md#keywordrecord)**
containing the actual **payments** to be escrowed by Zoe.
Every **Keyword** in **give** must also have a corresponding **payment**.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Every **Keyword** in **give** must also have a corresponding **payment**.
Every **Keyword** in **give** must have a corresponding **payment**.

@gibson042
Copy link
Member Author

@Chris-Hibbert updated with your suggestions.

@gibson042
Copy link
Member Author

Thanks all!

@gibson042
Copy link
Member Author

@erights Please remove or replace your "changes requested" review so this can merge.

Copy link
Member

@erights erights left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Please do look at all unresolved conversations to see if there's anything unaddressed before merging. Otherwise good to go. Awesome improvements, thanks!

@gibson042 gibson042 merged commit 88cbbec into main Dec 3, 2023
4 checks passed
@gibson042 gibson042 deleted the gibson-2023-11-improve-offer-documentation branch December 3, 2023 01:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants