Wire encodings, decoders and retries
This is the detail behind Decoding and
Calling: the encodings a provider's fields can be sent in, a
package's own decoders, which fields are decoded, and how retry: and
timed_out: work.
- The built-in encodings are ten, by these names:
unix_secondsandunix_milliseconds(anInstantas a whole number),iso_8601(anInstantwith any offset from UTC, which the contract refuses, since it writes onlyZ),day_month_year(aCalendarDate, the encoding Jobs and events and the Standard library name for file rows, here built for providers),text(anIntor aDecimalas text),comma_separated(a list of single values),base64(Textas the Base64 of its UTF-8),json_text(any value's JSON in a string),minor_units(Moneyin the one currency its type'scurrency:fixes, whichWire.minor_unitsneeds) andnumber(anIntor aDecimalas a JSON number, its digits kept as written both ways). The contract writes aDecimalas text and reads no number for one, so withoutnumbera provider sending2.50could not be read at all, not even by a package's own decoder. - Where they apply. On the provider's wire only: a call's input, its
answer and a webhook's event.
json.write, a route's answer and an event's payload write the field as the contract writes its type, so an app's clients never see a provider's encoding, where a field'swire_name:is its spelling everywhere. In the plan a field that says how it is sent has a codec of its own, holding its type's contract codec and how the provider sends it. - What each refuses.
wire:holdsWire.<name>naming one of the ten, on a field of a type that encoding holds; outside a provider package, besidedecode:orencode:, or naming anything else, it ispackage.wire_invalid. A value the provider sends that its encoding can't read is a fault naming the operation, the field and the rule (type,format,maxfor an instant past the years anInstantholds), and a list item holding a comma, whichcomma_separatedwould split, is the faultcomma_separatedwhen the call is sent. - A field's own functions.
decode:andencode:come together, eachlibrary.functionin the package's ownlibraries/, internal or public.decode:takes one value, the field as the provider sends it, and gives the field's type; it may fail, which is a fault.encode:takes the field's type and gives whatdecode:takes, and may not fail. Either named but not the package's, or of another shape, ispackage.wire_invalid; they count as the functions' use. That the pair round-trips, and that they read every recording, is checked under "Recordings". - An operation's whole decoder.
wire_output:anddecode:come together, withoutput:(package.operation_invalidotherwise):decode:takes thewire_output:type and gives theoutput:type. The answer is read fromoutput_at:aswire_output:, its own fields' encodings applied, and given whole todecode:. - Run at the call's site. The runtime asks the executor to run each
package function where the call is made; a
field decoder that fails is the problem
decodeon that field, and an operation's decoder that fails names how it ended (its failure's code or its fault's classification), never a value. - Only the fields read. Worked out per call site from its action's
body: when the call's value, or its
attempt's, is a variable's and every use of that variable is a field read, only those top-level fields are decoded and checked; the others holdnone, which no code can read. Fields inside a read field are decoded with it. Rules across the type's fields are checked only when every field is read. An operation decoded whole is read whole. - Numbers as written. An answer is parsed with Jadpo's own reader, so a number keeps the digits the provider wrote and an answer naming a member twice isn't JSON; a request's body and query are written with each number's digits as the input's codec wrote them.
retry:takesattempts:, 1 to 10, andwithin:, a duration up to 5 minutes, each defaulting to 3 and 30 seconds;connection.value_invalidotherwise. A call is sent again when it never left or the provider said it did nothing (408,429, itsin_use:code), whatever it changes, and when it may have acted (a server's error, no whole answer, no answer in time) only if it changes nothing or takes its key, under the same key. Waits are 200 milliseconds doubled before each further attempt, drawn evenly from zero (full jitter, from the host's randomness), or a408or429'sRetry-Afterin seconds; a wait pastwithin:stops the retrying. A host with no timer, as a test's, sends again at once and measures nothing. Each attempt goes through the capability seam and is logged, recorded and replayed as a call of its own.timed_out:The driver tells an answer that didn't come withintimeout:apart from other missing answers. Where the call'sattemptmapstimed_out:and the operation is safe to send again, the last attempt's timeout is the runtime'stimed_outfailure (kindtimed_out, 504), mapped to the app's failure with it as the cause; anywhere else it isunavailableoroutcome_unknown, as "How provider calls are made" says.timed_out:on an operation that changes something without a key isfailure.unknown_mapping, to a failure that isn'tunavailablefailure.mapping_kind; an operation listing no failures may still be attempted fortimed_out:alone.- What reviewers see. The package's surface writes an operation's
wire_output X decode Y, so the answer as sent shows beside its output, andjadpo package showgives it as "sent as"; the manifest gives a field'swire.
Markdown for agents: /docs/wire-encodings-decoders-and-retries.md.Built from Jadpo main at a707efb.