docs: remove unsupported second-plane language roadmap

This commit is contained in:
udo 2026-06-12 20:36:57 +00:00
parent 89b5499c8f
commit eb8f303f94

View File

@ -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. i.e. what dlopened `.so` units pay today.
Encode/decode is **not** part of internal component calls. It exists only at 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) ### 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 The supported model is one workspace peer model: languages must be able to
PIC linear-memory module that adopts a foreign allocator?* 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. - Join the workspace as PIC modules importing core symbols.
- Must adopt the core allocator (Rust: `#[global_allocator]`; Zig: allocator - Must adopt the core allocator (Rust: `#[global_allocator]`; Zig: allocator
parameter) and must not unwind across boundaries (`panic=abort` / 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>` calls. Idiomatic wrappers per language (e.g. Rust `DValue<'request>`
the borrow checker enforces the arena invariant). the borrow checker enforces the arena invariant).
**Plane B — runtime-carrying languages** (JS, Python, Go, C#, …): **Runtime-carrying/interpreted languages** (JS, Python, Go, C#, …) are not
- No support currently planned. 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):** If UCE later supports isolated or cross-trust-boundary components, those must be
cross-plane components do **not** receive the mutable context. They get an introduced as an explicit feature with an explicit API name and copied data
explicit interface — props in (copied by definition), rendered output and contract. They must not reuse normal `component(path, context)` semantics.
declared results back. Plane A keeps the full "here's the world, mutate it" Serialization boundaries and isolation boundaries remain the same lines, by
contract. A `component()` call must never silently change mutation semantics design.
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.
--- ---
@ -307,7 +305,8 @@ header := "UCEB" u8 version
``` ```
This encoding is a **versioned protocol** from day one (header byte). It is 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 UCEB1 encoding/decoding should also be exposed to the unit developer so
they can make use of fast serialization/deserialization: matching our existing 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 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. 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. 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 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 > wasm worker URL and adding worker-internal probes for workspace birth and
> component-call overhead budgets. > component-call overhead budgets.
**Phase 6 — second plane (deferred until wanted).** **Phase 6 — removed / not planned.**
Cross-instance call mechanism (props-in/output-out, UCEB1), first Plane B There is no planned second component plane for interpreted or runtime-carrying
language binding, loader enforcement of the cross-plane context rule (§4). 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 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 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** wholesale — the arena, done right). The contract is the **DValue C ABI**
inside the workspace (pointer semantics, no serialization) and the **UCEB1 inside the workspace (pointer semantics, no serialization) and the **UCEB1
wire encoding + handles** at every true address-space boundary (host 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 boundaries and isolation boundaries are the same lines; component calls stay
function calls; and the file stays the unit. function calls; and the file stays the unit.