Skip to content

MESH v0.18.0

Latest

Choose a tag to compare

@github-actions github-actions released this 31 Oct 06:34
· 2 commits to main since this release
db5f62f

MESH v0.18.0 release notes

Prepared 2026-10-30 (not yet published: v0.17.0 is the latest release).

v0.18 gives the units API one word per concept, and adds the context channel (direction decision C-1, K27). MPRX already used "instance" for an element of a component and for a repeat's key; the runtime used it again for one occurrence of a component with a unit. The prose already said "occurrence". Units are Provisional, so the cheapest time to rename is before the first outside dependent (direction decision C-4).

Highlights

  • The rename. Render.instances is Render.occurrences; intent.instance is intent.occurrence; a listed unit's instance is occurrence; a units entry's "instance" key is "occurrence"; the diagnostic runtime-unknown-instance is runtime-unknown-occurrence. In Rust: Render::occurrences, occurrences_to_json, Occurrence, Intent::occurrence(), RuntimeCode::UNKNOWN_OCCURRENCE. The WebAssembly results, render-v1's intent, the specification, the manuals and the conformance vectors (units/step-N.expected.occurrences.json) follow.
  • "Instance" keeps its MPRX meanings (an element of a component; a repeat's key, §9.10). Nothing about the language changes.
  • The old names work for one release, deprecated, and are removed in the next minor. See below.
  • The diagnostic runtime-unknown-instance is retired, never reused. A host that matched it must match runtime-unknown-occurrence.
  • The screen (openScreen) and the argument names on the intent, both Unreleased on the branch, ship in this release; the screen already said occurrence.
  • The context channel. A value many distant components need (a theme, a locale, the current user) reaches them without being threaded through every layer, declared and type-checked. See below.

The context channel

"context": { "theme": { "kind": "enum", "values": ["light", "dark"] } },
"components": { "badge": { "props": {}, "events": {}, "commands": {}, "scope": {}, "uses": ["theme"] }, ... }
  • Declared once, used by name. The manifest's top-level context declares each name and its type. A component lists what it reads in uses; those names join its scope read-only, and mesh check type-checks every read before anything runs. A component that doesn't list a name can't read it: no inheritance, no lookup. manifest-unknown-context is a name the context doesn't declare; manifest-context-clash is one that is also a prop or scope name, or listed twice.
  • Given beside the snapshot. render({ program, model, snapshot, context }); update(render, snapshot, units, context) (without context, the render's own); in Rust render_context and update_with_context. A value that doesn't fit is reported at $context.<name>. Dispatch evaluates against the context the render had.
  • Changed by changes. An edit whose path starts { "context": name } edits that value: { "op": "set", "path": [{ "context": "theme" }], "value": "dark" }. Every node that reads it is evaluated again (in this release the whole tree is rendered again on a context change; the patches are still the difference).
  • Where it is read. A snippet, and the content a slot places, read the context of the template that declared them. Commands are not context. A subtree override ({#with}) and per-subtree providers are left for later.
  • Use props first. Context is for values many distant components need; a value one or two levels down is a prop.

It is Tier 2 and Provisional. The specification gains §9.11, and §9.1 reads "no implicit names: a context name is in scope only where the manifest says the component uses it". The screen takes it too: screen.show(snapshot, context?), which keeps the values last shown when given none.

Migrating

Was Is
render.instances / Render::instances() render.occurrences / Render::occurrences()
each.instance (a listed unit), intent.instance each.occurrence, intent.occurrence (Rust: intent.occurrence())
[ { "instance": key, "state": ... } ] (Rust Units::from_json) "occurrence" (the old key is still read; both in one entry is refused)
mesh_runtime::Instance, instances_to_json() Occurrence, occurrences_to_json()
runtime-unknown-instance runtime-unknown-occurrence

What the runtime writes (the JSON of an intent or of the occurrences, the module's result documents) has the new names only. The JavaScript aliases are not enumerable, so deep comparisons and JSON.stringify see the new shape. In Rust, Intent is Stable and its fields are public, so the instance field stays under its old name, #[deprecated], and Intent::occurrence() reads it: renaming it or adding a second field would break code that builds an Intent. A Rust host that builds Intent { .. } keeps compiling (with a deprecation warning for the field). The field is renamed in the release that removes the aliases.

Compatibility

A program, a manifest, a snapshot and every other document are unchanged; context and uses are new and optional. A manifest that has either is refused by an older MESH (manifest-unknown-property). render-v1, the patches and the intent are unchanged by the context channel. In Rust the new entry points sit beside the old ones, which are the same operations with no context, and Component and Declaration (both #[non_exhaustive]) gain uses and Context. A host that reads render-v1 intents or the module's result documents by the old property names must read the new ones. The module and the package still have to be the same version.

North-star scorecard

M2 (one term per concept): the "instance" collision is removed; M2 stays ◐ while the other collisions remain. Tier 2 (Provisional).

C1 (a value reaches a deep component without threading): ✗ → ✓, the context channel. C2 (the channel is explicit and checkable): not applicable → ✓, declared in the manifest and type-checked by mesh check ahead of run. Tier 2 (Provisional). No audit regresses.

Verification

cargo test --workspace; the runtime package's tests (a new test for each of the old names in both runtimes; the context channel through the package); the conformance vectors for units under their new names, and context/ in both runtimes. Not run in this environment: the runtime package's size test (needs binaryen) and the browser tests.