From eb8f303f94f0f43699eca7cd6474eedaef1ed711 Mon Sep 17 00:00:00 2001 From: udo Date: Fri, 12 Jun 2026 20:36:57 +0000 Subject: [PATCH] docs: remove unsupported second-plane language roadmap --- WASM-PROPOSAL.md | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/WASM-PROPOSAL.md b/WASM-PROPOSAL.md index 0d9dc92..7f7fd2d 100644 --- a/WASM-PROPOSAL.md +++ b/WASM-PROPOSAL.md @@ -190,7 +190,7 @@ set of headers — the C/C++ ABI is intact across module boundaries. Therefore: i.e. what dlopened `.so` units pay today. Encode/decode is **not** part of internal component calls. It exists only at -the membrane (§3.3) and on the cross-instance plane (§4). +the membrane (§3.3) and at any future explicit isolation boundary (§4). ### 3.5 The DValue C ABI (load-bearing, build it first) @@ -211,12 +211,13 @@ testability) and de-risks the rest. --- -## 4. Two component-call planes / multi-language support +## 4. Component-call model / supported languages -The design stratifies languages by one question: *can the toolchain produce a -PIC linear-memory module that adopts a foreign allocator?* +The supported model is one workspace peer model: languages must be able to +produce PIC linear-memory modules that adopt the core allocator and join the +workspace. -**Plane A — workspace peers** (C++, C, Rust, Zig, …): +**Workspace peers** (C++, C, Rust, Zig, …): - Join the workspace as PIC modules importing core symbols. - Must adopt the core allocator (Rust: `#[global_allocator]`; Zig: allocator parameter) and must not unwind across boundaries (`panic=abort` / @@ -225,19 +226,16 @@ PIC linear-memory module that adopts a foreign allocator?* calls. Idiomatic wrappers per language (e.g. Rust `DValue<'request>` — the borrow checker enforces the arena invariant). -**Plane B — runtime-carrying languages** (JS, Python, Go, C#, …): -- No support currently planned. +**Runtime-carrying/interpreted languages** (JS, Python, Go, C#, …) are not +supported and are not on the roadmap. UCE will not add an alternate component +plane that silently changes `component()` from mutable in-workspace reference +semantics into copied RPC semantics. -**The semantic rule (enforced by the loader, not by convention):** -cross-plane components do **not** receive the mutable context. They get an -explicit interface — props in (copied by definition), rendered output and -declared results back. Plane A keeps the full "here's the world, mutate it" -contract. A `component()` call must never silently change mutation semantics -based on the callee's implementation language. - -The cross-instance call mechanism is shared by: Plane B units, and future -cross-trust-boundary components (multi-tenant). Serialization boundaries and -isolation boundaries are the same lines, by design. +If UCE later supports isolated or cross-trust-boundary components, those must be +introduced as an explicit feature with an explicit API name and copied data +contract. They must not reuse normal `component(path, context)` semantics. +Serialization boundaries and isolation boundaries remain the same lines, by +design. --- @@ -307,7 +305,8 @@ header := "UCEB" u8 version ``` This encoding is a **versioned protocol** from day one (header byte). It is -the Plane B contract and the membrane format; internal calls never see it. +for future explicit isolation-boundary contracts and the membrane format; +internal calls never see it. UCEB1 encoding/decoding should also be exposed to the unit developer so they can make use of fast serialization/deserialization: matching our existing @@ -454,7 +453,7 @@ existing suite; ABI doc checked in. 1. ucb_encode(DValue value) deep-copies the whole tree (dvalue.cpp:962, same signature in the header). DValue copy is a full recursive map+string clone, and this function is the future membrane hot path — the request context will pass through it on every request in Phase 2. Should be const DValue& (the function only reads). Same nit for bool ucb_decode(String encoded, ...) at :971 — a by-value String copy of what may be a large document; const String& matches. -2. 'P' values ship the raw pointer address on the wire (ucb_node_scalar, dvalue.cpp:833, the 'P' case). The ABI doc explicitly says "pointer/reference identity is intentionally not part of the wire contract," but the implementation encodes std::to_string((u64)ptr) — a meaningless number on the receiving side and an ASLR address disclosure the day UCEB1 crosses a trust boundary (Plane B / multi-tenant is the stated +2. 'P' values ship the raw pointer address on the wire (ucb_node_scalar, dvalue.cpp:833, the 'P' case). The ABI doc explicitly says "pointer/reference identity is intentionally not part of the wire contract," but the implementation encodes std::to_string((u64)ptr) — a meaningless number on the receiving side and an ASLR address disclosure the day UCEB1 crosses a trust boundary (multi-tenant isolation is the stated endgame). It's consistent with native to_string, but the wire is a different context: I'd encode "" for 'P' and note it in the doc. 3. f64 fidelity on the wire. 'F' encodes through std::to_string → fixed 6 decimals. That's faithful to native to_string, but the membrane makes it new lossiness: today an 'F' value never round-trips through its string form unless page code asks; in Phase 2 every float in the context will. 1e-7 becomes "0.000000" → decodes to 0. Since the scalar is just a string, switching 'F' to shortest-round-trip formatting @@ -621,9 +620,11 @@ call cost. Exit: numbers published in this document, all tests and reviews pass. > wasm worker URL and adding worker-internal probes for workspace birth and > component-call overhead budgets. -**Phase 6 — second plane (deferred until wanted).** -Cross-instance call mechanism (props-in/output-out, UCEB1), first Plane B -language binding, loader enforcement of the cross-plane context rule (§4). +**Phase 6 — removed / not planned.** +There is no planned second component plane for interpreted or runtime-carrying +languages. Future work after Phase 5 should continue productionizing the single +workspace-peer WASM backend unless Udo explicitly approves a separate isolated +component feature with a new API name and copied-data semantics. The native `.so` backend remains in-tree (as a reference) and selectable by config but we switch over to the wasm backend as soon as it's available and test @@ -671,6 +672,6 @@ request; shared memory + table; born from a core-only CoW snapshot; dropped wholesale — the arena, done right). The contract is the **DValue C ABI** inside the workspace (pointer semantics, no serialization) and the **UCEB1 wire encoding + handles** at every true address-space boundary (host -membrane, Plane B languages, future trust boundaries). Serialization +membrane and future explicit trust boundaries). Serialization boundaries and isolation boundaries are the same lines; component calls stay function calls; and the file stays the unit.