Research phase for browser-native swactor runtime: - constraints.md: wasm-threads (SharedArrayBuffer), Rust-only actors, COOP/COEP required, no new modules in src/ - research_synthesis.md: P0-P4 priority ranking, platform dependency analysis, ecosystem comparison (Lunatic, wasmCloud, Actix) - 6 feature-stage docs: platform abstraction → single-worker → multi-worker parallelism → feature parity → transport → DX - Key decision: SharedArrayBuffer + wasm-threads over postMessage isolation (swactor's shared-memory architecture demands it) Authored by Claude, lovingly guided by Zachery Aaron Shores-Chmielewski
3.2 KiB
3.2 KiB
Constraints — In-Browser Swactor Runtime
Threading Model
- wasm-threads is mandatory — the runtime uses SharedArrayBuffer + WebAssembly atomics for multi-worker parallelism. There is no single-threaded degraded mode for MVP.
- Browsers must serve pages with COOP/COEP headers:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
- Build requires nightly Rust +
-Z build-std=std,panic_abort+ target features+atomics,+bulk-memory,+mutable-globals.
Architecture Rules
- Platform abstractions live in core swactor (
src/), gated by#[cfg(target_arch = "wasm32")]. They do not belong in the wasm crate. - Do not add new modules to
src/— modify existing files only (TASK.md style rule). - Do not restructure existing module boundaries. The abstraction is a thin layer (type aliases, cfg-gated imports), not a trait-based HAL.
- The browser crate (
crates/wasm-browser/or evolvedcrates/wasm/) is a thin wasm-bindgen shell. All scheduling, routing, and actor logic stays in core Rust.
Actor Model
- Rust-only actors — actors are written in Rust and compiled to wasm. JavaScript does not define actor behavior.
- JS interacts through the wasm-bindgen API: create runtime, spawn actors (by registered type), send messages, receive results.
- Actor types are registered at compile time via Rust generics, not dynamically from JS.
Performance Priorities
- Maximize throughput: auto-scheduling via
setTimeout(0)tight loop, notrequestAnimationFrame(which caps at display refresh rate). - Web Worker count defaults to
navigator.hardwareConcurrencyfor full core utilization. - Zero-copy where possible: SharedArrayBuffer eliminates serialization between workers.
- Minimize JS↔Wasm boundary crossings — batch operations where feasible.
Feature Scope
- All core features that compile for wasm32: spawn, send, receive, tick, actor lifecycle, watching, extensions.
- swactor-std features (naming, groups, monitoring) should work if they compile.
- Transport: WebSocket adapter for distributed clusters. STUN/TURN (WebRTC) deferred to later.
- Features that require OS primitives not available in wasm (filesystem, raw TCP) are excluded.
Testing
- Tests must pass on both native (
cargo test) and wasm targets. - Wasm tests use
wasm-pack test --headless --chromeor Node.js with--experimental-wasm-threads. - No test-only code paths that diverge native vs wasm behavior — if it works differently, it's a bug.
- Prefer scenario tests over structural tests (per project testing rules).
Dependencies
web-time— drop-in replacement forstd::time::Instanton wasm32wasm-bindgen+js-sys+web-sys— browser API bindings (in the wasm crate only, not core)gloo-timers— optional, for ergonomic setTimeout/setInterval- No new dependencies in core swactor beyond
web-time(which is no-op on native)
What We Don't Do
- No async/await runtime (tokio, async-std) — swactor is synchronous tick-based
- No Emscripten — target is
wasm32-unknown-unknownonly - No WASI — browser environment, not server-side wasm
- No JS actor definitions — Rust only
- No polyfills for missing atomics — if SharedArrayBuffer isn't available, the runtime doesn't start