ontoref-code/examples/catalog-extension/04-wasm/README.md
2026-07-10 01:44:59 +01:00

4.2 KiB

Path D — kind = 'Wasm

Phase B per ADR-030 — declarable today, executive backend deferred. The op body is a WASM component implementing a WIT-typed interface; the daemon (when built with --features wasm) hosts it via wasmtime inside an explicit capability sandbox.

Files

File Purpose
render_provisioning_report.ncl Catalog declaration with kind = 'Wasm and a fully-populated body
render_provisioning_report.wit WIT interface — the host/guest contract

What the body declares

Field Value Meaning
module_path .ontoref/catalog/wasm/render_provisioning_report.wasm Built WASM artefact, project-relative
export_name ontoref:catalog/op#render Exported function the host calls
capabilities ["fs:read:.ontology/provisioning/", "fs:read:.ontoref/catalog/", "net:none"] Explicit grant set — anything else traps

Today's runtime behaviour

Dispatching against a stock daemon returns:

HTTP/1.1 501 Not Implemented
{
  "error": "missing_executive_backend",
  "kind":  "Wasm",
  "op_id": "render_provisioning_report",
  "hint":  "rebuild ontoref-daemon --features wasm (awaiting ADR-030 T3/T4/T5 trigger)"
}

This is intentional per ADR-034 constraint non-rust-kinds-declarable-not-executable-without-flag. The op declaration is a first-class catalog entry that consumers can read cross-project via ADR-028 content-addressing right now.

Building the WASM artefact (when the executive backend lands)

# 1. Author the implementation against the WIT interface — any source
#    language that supports the component model: Rust, AssemblyScript,
#    Go (with tinygo), Zig, Python (via Pyodide), …

# 2. For a Rust implementation:
cargo build -p render-provisioning-report --target wasm32-unknown-unknown --release

# 3. Convert the core wasm to a component:
wasm-tools component new \
  target/wasm32-unknown-unknown/release/render_provisioning_report.wasm \
  -o .ontoref/catalog/wasm/render_provisioning_report.wasm

Why WASM is Phase B (deferred)

Per ADR-030 the WASM backend awaits one of:

  • T3 — cross-instance ops dispatch becomes the bottleneck (HTTP IPC chain in Path B Sidecar exceeds acceptable latency)
  • T4 — toolchain divergence — an instance wants ops in Go / Python / AssemblyScript and dynlib is too brittle
  • T5 — untrusted ops authors — the deployment must sandbox ops from outside the instance's control

None of these have fired empirically. Path B (Sidecar) covers the shared-domain near-term case at ~80 LOC of daemon proxy; WASM lands when concrete pressure justifies the wasmtime dependency.

Key properties

  • evaluate_ondaod is mandatory — the host invokes ondaod discipline BEFORE entering the sandbox. The WASM module cannot reach the ondaod context.
  • Witness honestypayload_kind = "wasm_call_envelope". The daemon's Ed25519 signature attests the inputs it passed and the outputs it received; it does NOT claim to attest the WASM-internal computation (the sandbox is honest about being a black box).
  • Capability sandbox — every fs/net interaction must be in the capabilities list. Anything else returns a wasmtime host trap. Designed for the T5 untrusted-author case.
  • wasmtime is NOT in the default daemon build — ADR-034 constraint wasmtime-not-in-default-daemon-build. Honours protocol-not-runtime axiom (invariant=true).

When NOT to use

  • Your op is part of the ontoref piloto → Path A 'Rust.
  • Your project is a shared-domain instance and the bottleneck is process management overhead, not the IPC boundary → Path B 'Sidecar is the right Phase A answer.
  • The op is a trivial NCL data-transform → Path C 'NclTransform (lower complexity than WASM, no wasmtime needed).

References