Skip to content

kitchen-sink streams/futures + instantiate untranslated-artifacts (A3) - #57

Merged
lann merged 1 commit into
mainfrom
examples-streams-dx
Aug 10, 2026
Merged

kitchen-sink streams/futures + instantiate untranslated-artifacts (A3)#57
lann merged 1 commit into
mainfrom
examples-streams-dx

Conversation

@lann

@lann lann commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

From the examples DX review (operator suggestions, both adopted in adjusted form):

A3 — instantiate({ componentBytes, translator }, imports): translation runs internally; translator takes the shim wasm bytes or a shared Translator (the multi-component pattern). hello-world's host is now a single call from bytes to instance. Pinned both spellings in untranslated_artifacts_test.ts; contract Status + §Module wiring updated.

Byte imports — investigated, deferred, documented: type: "bytes" is Deno-unstable (2.9) and its config opt-in only works at the workspace root, which would silently break the examples' copy-out contract; type: "text" (which IS flagless) corrupts binaries irreversibly — measured: the hello component decodes with 2,206 U+FFFD replacements, re-encodes 20,505 → 24,898 bytes. Examples stay on Deno.readFile + scoped --allow-read (stable, location-independent), with the future flag-free shape noted in comments. run.sh now type-checks before running.

kitchen-sink §8/§9 — streams and futures, WIT → guest → host:

  • tally(stream<u32>) -> u64: array and ReadableStream passed as natural producers;
  • countdown(u32) -> stream<u32>: guest-produced Stream handle, for await in chunks;
  • promised-double(future<u32>): a plain Promise where a future is expected;
  • deferred-answer() -> future<u32>: the eager Future handle exception to Promise-shaped exports, held → inspected → awaited.

Guest: no async: macro option — WIT's own async func markers drive per-function codegen (the test-suite fixture pattern), keeping the sync imports sync-lowered so the @suspending demo stays honest; producer halves use the rendezvous + spawn_local pattern from the stream-echo/future-user fixtures.

Gates: examples, test-runtime 343/0 (commit message says 338 — undercount, actual 343), wasi-shims/ct-runner/bundle, conformance 1254/0 (0 unexpected/stale), sched-seeds, shells.

…slated artifacts (A3)

Three related changes from the examples DX review.

A3 (contracts/embedder-api.md v0.2): `instantiate` also accepts
`{ componentBytes, translator }` where translator is the shim wasm bytes
or a shared Translator instance, translating internally — bytes in,
instance out. requiredImports still takes a plan (translate explicitly to
inspect the surface first). Pinned by
tests/embedder/untranslated_artifacts_test.ts (both translator
spellings). This collapses hello-world's host to a single instantiate
call and removes the last boilerplate a first-time embedder has to
understand before seeing output.

Byte-import decision, recorded after empirical probes: `import ... with
{ type: "bytes" }` would make the hosts permission-flag-free, but it is
Deno-unstable as of 2.9 (--unstable-raw-imports) and the unstable opt-in
only takes effect at the WORKSPACE ROOT — a copied-out example directory
would silently lose it, breaking the examples' copy-out contract. The
flagless-but-stable alternative, `type: "text"`, corrupts binaries
irreversibly (lossy UTF-8: the hello component decodes with 2206
U+FFFD replacements, re-encoding 20505 -> 24898 bytes). Examples
therefore stay on Deno.readFile + scoped --allow-read, with the
bytes-import future noted in a comment; run.sh now also type-checks
(deno check) before running.

kitchen-sink gains §8 streams and §9 futures, WIT -> guest -> host:

  - tally: async func(stream<u32>) -> u64 — the host passes natural
    producers (a finite array; a ReadableStream) where the guest expects
    a stream; the runtime owns pumping and close-on-end.
  - countdown: async func(u32) -> stream<u32> — a guest-produced stream
    arrives as a Stream<u32> handle; for-await yields CHUNKS (number[]
    batches), asserted flattened.
  - promised-double: async func(future<u32>) -> u32 — a plain Promise
    works where a future is expected.
  - deferred-answer: async func() -> future<u32> — the future-typed
    result is the one exception to Promise-shaped exports: an EAGER
    Future handle, returned synchronously (a Promise wrapper would adopt
    the thenable and make drop/cancel unreachable); the host holds it,
    checks .drop exists, then awaits it for the value.

Guest side: no `async:` macro option — the WIT's own `async func`
markers drive per-function codegen (the test-suite fixture's pattern),
which is load-bearing here: the sync imports stay sync-LOWERED so the
suspending-import demonstration remains honest. Producer halves
(countdown, deferred-answer) follow the fixture rendezvous pattern:
writes complete only when the peer receives, so they run in spawn_local
tasks (wit-bindgen async-spawn feature) while the reader half returns.
Component validation gains the cm-async feature in run.sh.

READMEs updated (kitchen-sink table + notice items; index row); the
"deliberately absent" list shrinks to async-typed imports and
error-context.

Gates: examples, test-runtime (338/0 incl. the new A3 pins),
wasi-shims/ct-runner/bundle, conformance (1254/0, 0 unexpected, 0
stale), sched-seeds, shells — all green.
@lann
lann enabled auto-merge August 10, 2026 22:06
@lann
lann merged commit 9ef9969 into main Aug 10, 2026
4 checks passed
@lannbot
lannbot deleted the examples-streams-dx branch August 23, 2026 16:51
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.

1 participant