Repository navigation
client: the envelope form of a program, a surface over the $proc form (coeval M7) - #133
Merged
Merged
Conversation
… (coeval M7)
coeval decided (D6, D9, D10) that a document is an envelope { type, value }
with the optional header keys name and own; a call is an envelope whose
type is a procedure path (an array of keys) and whose value is the input;
a reference is { type: "ref", value: [root, step, ...] }.
- procedures/envelope.ts: isEnvelopeProgram, fromEnvelopeProgram and
toEnvelopeProgram, and the types EnvelopeProgram, EnvelopeRef,
EnvelopeLiteral and EnvelopePath. Exported from ".", "./browser" and
"./procedures". The interpreter (hydrateInput) does not change: the
envelope form converts to the $proc form.
- A call envelope gives { $proc, input }, and the header name gives $name.
A ref into the world ({ type: "ref", value: ["world", ...path] }) is
also a type. A value of null gives a call without input (the procedure
gets undefined, and passThrough applies); a literal null gives null.
- ["names", "last"] gives $last, ["names", n, ...fields] gives "n.f1.f2"
(each key a string without a dot or an integer >= 0). Another root
(self, world, event, caps) is an error that names the root.
- { type: "literal", value } gives { $literal: value }. In an envelope
program, an object with a $proc, $ref or $literal key, or a runtime
ProcedureRef, is data: it goes into a $literal.
- No $when in the envelope form. toEnvelopeProgram refuses $when, other
keys on a call or a $ref, a ref to a step named "last", and data that
the envelope form reads in another way when it holds a construct. The
round trip gives the same program, except a call with input null and
such data, which come back in a $literal with the same values.
- Client.exec/execStream accept an envelope root: it converts first, then
runs as before; exec(program, input) merges input as for a $proc root.
Every other form and error message is unchanged.
- Tests: the PROGRAM-FORMAT examples in both forms (results, conversion
both ways), escapes, errors, exec/execStream, define, and a fast-check
property that the round trip hydrates to the same value.
- test/api/public-api.txt updated on purpose (UPDATE_API_SNAPSHOT=1): the
new exports and the widened exec/execStream parameter.
- PROGRAM-FORMAT.md: new section 11 "The envelope form" (mapping table,
example, rules); "Open questions" is now section 12, with the two
in-document references and the pointer in deep-dive STATUS.md updated.
- Changeset: patch of the client group (additive, D13).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The envelope form of a program (coeval M7)
coeval decided (D6, D9, D10) that a document is an envelope
{ type, value }(header keysname,own), a call is an envelope whosetypeis a procedure path (an array of keys) and whosevalueis the input, and a reference is{ "type": "ref", "value": [root, step, ...] }.This PR adds the envelope form as a surface that converts to the native
$procform. The interpreter (hydrateInput) does not change. The root of a program decides its form: an envelope inside the input of a$procprogram stays plain data, so no existing program changes behavior.What changes
packages/client/src/procedures/envelope.ts(new):isEnvelopeProgram,fromEnvelopeProgram,toEnvelopeProgram, and the typesEnvelopeProgram,EnvelopeRef,EnvelopeLiteral,EnvelopePath. Exported from.,./browserand./procedures.Client.exec()/Client.execStream()accept an envelope root. It converts first, then runs as before.exec(program, input)mergesinputexactly as for a$procroot. Every other form and error message is unchanged.PROGRAM-FORMAT.md: new section 11 "The envelope form" (mapping table, a full example, the rules). "Open questions" becomes section 12, and its references are updated (two in the document, one indeep-dive-2026-10/STATUS.md).patchof the client group (additive, D13).The mapping
$procform{ "type": ["client","add"], "value": input }{ "$proc": ["client","add"], "input": input }{ "type": { "type": "ref", "value": ["world","client","add"] }, "value": input }{ "type": path, "value": null }{ "$proc": path }(no input: the procedure getsundefined, andpassThroughapplies)"name": "sum""$name": "sum"{ "type": "ref", "value": ["names","sum","total"] }{ "$ref": "sum.total" }{ "type": "ref", "value": ["names","last"] }{ "$ref": "$last" }{ "type": "literal", "value": x }{ "$literal": x }$proc,$refor$literalkey, or a runtimeProcedureRef{ "$literal": object }(data)$when: a program that needs it keeps the$procformErrors: a ref root other than
names(the message names the root and says that client programs read onlynames), a ref key with a dot or a key that is not an integer of 0 or more, a header on a ref or a literal,ownon a call, a non-stringname, a call type that is a ref but not into the world, and cycles or depth overMAX_DATA_DEPTH.toEnvelopeProgramrefuses$when, extra keys on a call or a$ref, a$refto a step namedlast, and data that the envelope form reads differently when that data holds a construct. The round tripfromEnvelopeProgram(toEnvelopeProgram(p))deep-equalsp, with two documented exceptions that give the same values: a call withinput: null, and envelope-shaped (or$-keyed) data. Both come back wrapped in$literal.Tests
envelope.test.ts(45 tests): the PROGRAM-FORMAT examples in both forms (strict conversion both ways, and the same results throughexec),procedure.definewith an envelope body, world-ref types,exec(program, input),execStream, a call without input andpassThrough, the escapes, old$procprograms keeping envelopes as data, the errors, and a fast-check property: whentoEnvelopeProgramaccepts a program, the round trip hydrates to the same value. At 5000 runs that is about 4500 accepted programs, about 2250 of them with calls.test/api/public-api.txtwas updated on purpose withUPDATE_API_SNAPSHOT=1(the snapshot test only). The update adds the new exports and widens theexecandexecStreamparameter.Local runs:
pnpm --filter @procedures/client build,typecheckandtest(2112 passed),node .github/scripts/typecheck-tests.mjs client, andpnpm lint:ste(0 errors; the warnings were already on main).🤖 Generated with Claude Code