swactor/big-feature-phase/notes/constraints.md
Claude 63cba1c4eb research: in-browser runtime Cycle 0
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
2026-02-13 20:20:09 +07:00

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-origin
    • Cross-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 evolved crates/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, not requestAnimationFrame (which caps at display refresh rate).
  • Web Worker count defaults to navigator.hardwareConcurrency for 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 --chrome or 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 for std::time::Instant on wasm32
  • wasm-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-unknown only
  • 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