Skip to content

ADR 0014 phase 2: an app's Rust components in the wasm service - #445

Merged
2 commits merged into
mainfrom
feat/wasm-components-service
Oct 10, 2026
Merged

2 commits merged into
mainfrom
feat/wasm-components-service

Conversation

@ymote

@ymote ymote commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

ADR 0014 phase 2, OctoSense's part: the shell's wasm service runs an app's own components. A component is an ordinary Rust crate built with cargo build --target wasm32-wasip2, or with App Flow's tools/octo wasm build. The app's script calls each function as wasm.<function> with JSON, with no glue. Stacked on #436 (phase 1, the runtime); merge that first.

What changes

  • The service (crates/shell/src/wasm_service.rs):
    • It loads components from fns/ beside core modules.
    • It keeps one instance per component between calls, so a component can hold a document or a cache. A trap, the deadline, a changed grant or the worker's exit (after a minute idle) ends the instance.
    • Function names are snake_case, and either spelling is accepted.
    • The input limit is 8 MiB.
    • wasm.functions describes components: their exports with WIT signatures, and the instance's state.
  • Files:
    • Where: the app's own storage folder, the jail its script's fs.* sees, is the component's /. The service decides it per call by the engines' rules (areas::app_area): none without storage, and none without a signed-in account for an app with accounts.
    • Quota, per write (crates/wasm-host/src/component/files.rs):
      • Calls that grow a file are charged against what is left of the quota.
      • Truncating and deleting give bytes back, so a component at its quota can still free space.
      • A refused write fails inside the component. Through wasi-libc it shows as an I/O error, and the call's error adds "a write was refused: the storage budget is used up".
    • Speed: file writes run on the worker's own thread.
  • App Hub pin 769e9ee3 (shell: a hosted module may refuse a close and ask first (makepad#65) #186): the store admits components under wasm-components-v1.
  • Runtime fixes: a one-item array is accepted as the positional arguments of a one-parameter function. The test guest gained functions that cover append, set-size and delete, and a hyphenated record and enum.
  • Measurements and docs:
    • cargo run --release -p octosense-wasm-host --example measure_component measures a component against a module and native Rust.
    • ADR 0014 records the figures and the quota decision.
    • docs/wasm.md (en, zh-CN) gains a Components section.

Verified (macOS, Apple M5 Max, Rust 1.97.1)

Command Result
cargo test --locked -p octosense-wasm-host component 10, guest 7, runtime 14: all pass, including the storage budget (truncate refund, append, set-size, delete)
cd phone && cargo test --locked --features mobile-apps -p octosense-shell wasm_service::tests 6 pass. New: a_components_instance_keeps_state_and_its_files_stay_in_the_apps_storage (typed JSON, state, the app's folder, the quota, no folder without storage) and a_shipped_component_answers_its_apps_script (a system app through App Hub's admission).
python3 tools/setup.py --check --cargo exit 0
The developer's flow: octo new + octo wasm new + octo wasm build (App Flow #180), the bundle shipped through admission, called as the script would wasm.greet("Ada") → "Hello, Ada!"; wasm.count → {words: 3, lines: 2}; wasm.parse_number("two") → error "two" is not a number; wasm.calls → 1, then 2; save_note/read_note use the app's folder
measure_component compile 37.5 ms (313 KiB), from cache 3.6 ms, instantiate 0.09 ms; Markdown → HTML 468 µs (module 400 µs, native 183 µs)

Unverified: components on a phone (Android links the same runtime, but nothing has run on a device yet), and a desktop run with a component app.

🤖 Generated with Claude Code

ymote and others added 2 commits October 9, 2026 16:15
…orage quota

The shell's wasm service loads components from fns/ beside modules, keeps
one instance per component between calls, gives it the app's storage
folder by the engines' rules, and charges what each write adds against
what is left of the app's quota (wasm-host component/files.rs). Writes run
on the worker thread. Typed JSON accepts a one-item positional array.
Measurements, docs (en, zh-CN) and tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
App Hub #186 admits WebAssembly components when the manifest requires
wasm-components-v1, validates their imports (only the WASI packages a host
scopes to the app) and tells reviewers what each reaches. With the store
on it, a component shipped as a system app goes through admission, and the
new service test calls it as the app's script would: typed JSON, the
instance's state from one request to the next, no folder without storage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ymote
ymote changed the base branch from feat/wasm-components to main October 10, 2026 01:32
@ymote ymote closed this pull request by merging all changes into main in 80b2769 Oct 10, 2026
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