swactor/big-feature-phase/notes/research_synthesis.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

5.5 KiB

Research Synthesis — In-Browser Swactor Runtime

Ecosystem Landscape

No established Rust actor framework runs natively in browsers. The closest projects:

  • Lunatic — Erlang-inspired Wasm actor runtime using wasmtime (server-side, not browser). Uses preemptive scheduling and work-stealing. Not applicable to browser constraints.
  • wasmCloud — CNCF distributed actor platform. Single-threaded actors, NATS-backed lattice. Cloud/edge focus, no browser target.
  • Actix — Tokio-dependent, network stack doesn't compile for wasm32. Community attempts to port failed due to net2/tokio dependencies.

Implication: swactor would be the first Rust actor runtime with true multi-threaded browser execution via wasm-threads. This is a differentiated position.

Existing Work in This Codebase

Component Status Notes
crates/wasm/ Basic PoC Hardcoded Counter/Relay actors, manual tick, u32-only messages
no_random feature Working Deterministic address generation without getrandom
tick() method Working Single-threaded tick for manual driving
Actor watching In core ExitReason, ActorExited, on_actor_exit, WatchRegistry
swactor-std Complete StdExtension, naming, groups, monitoring, supervisor

Platform Dependencies Analysis

Works as-is with wasm-threads

  • crossbeam-queue (ArrayQueue, SegQueue) — uses core::sync::atomic
  • std::sync::{Mutex, RwLock} — stdlib uses futex on wasm with atomics
  • std::sync::atomic::* — maps to wasm atomic instructions
  • Arc<T> — works with atomics
  • std::sync::OnceLock — works with atomics

Requires platform abstraction (4 items)

  1. std::thread::spawn → Web Worker via web-sys::Worker
  2. thread::park_timeout / Thread::unpark → Atomics.wait / Atomics.notify
  3. thread::yield_now → no-op (or Atomics.wait(0) as hint)
  4. std::time::Instant → web_time::Instant (drop-in crate)

Priority Ranking

P0 — Must Have (enables everything else)

  1. Platform abstraction layer — cfg-gated replacements for thread spawn, park/unpark, yield, Instant. Core swactor compiles for wasm32 with atomics.
  2. Single-worker browser runtime — Prove the runtime works in a browser. One Web Worker, auto-scheduled tick loop, generic JS API for spawn/send/recv.
  3. Multi-worker parallelism — N Web Workers sharing runtime state via SharedArrayBuffer. Full utilization of browser CPU cores.

P1 — Should Have (full actor system)

  1. Actor watching in browser — Death notifications, exit reasons. Already in core, just needs to compile and pass wasm tests.
  2. swactor-std in browser — Naming, groups, monitoring extensions. Compile and test for wasm32.
  3. Stats and introspection — Runtime stats accessible from JS. Worker info, actor counts, message throughput.

P2 — Important (distributed peer)

  1. WebSocket transport — Adapter implementing swactor's transport traits over WebSocket. Browser node joins a distributed cluster.
  2. Browser-to-browser transport foundation — WebRTC DataChannel scaffolding for future STUN/TURN.

P3 — Nice to Have (developer experience)

  1. TypeScript type generation — Derive TS interfaces from Rust actor message types.
  2. Build tooling — wasm-pack wrapper script, example project template, CI configuration.
  3. Browser dev tools — Actor inspector, message flow visualization, performance profiling.

P4 — Future (out of scope for this feature phase)

  1. STUN/TURN integration — Full NAT traversal for peer-to-peer browser connections.
  2. Hot code reload — Swap actor implementations without restarting the runtime.
  3. Wasm component model — Migrate from wasm-bindgen to component model when stabilized.

Key Design Decisions

Decision Choice Rationale
Threading model SharedArrayBuffer + wasm-threads swactor's shared-memory architecture (Arc, crossbeam queues, atomics) maps directly. postMessage isolation would require a rewrite.
Scheduling setTimeout(0) tight loop requestAnimationFrame caps at 60Hz. setTimeout(0) gives ~4ms resolution, sufficient for actor ticks. For rendering-coupled actors, RAF can be opt-in.
Actor definition Rust only Keeps the type system intact. JS actors would require dynamic dispatch and lose compile-time guarantees.
Platform abstraction approach cfg-gated type aliases + inline functions Minimal invasion. No trait-based HAL, no new modules. Just swap std::time::Instant → web_time::Instant etc.
Browser crate location New crates/wasm-browser/ Clean separation from the existing PoC. The old crates/wasm/ can be deprecated or kept as a minimal example.

Risk Assessment

Risk Likelihood Impact Mitigation
crossbeam-queue doesn't compile for wasm32+atomics Low High Test early in Stage 1. Fallback: thin wrapper over VecDeque behind cfg.
COOP/COEP headers break third-party integrations Medium Medium Document clearly. This is the standard trade-off for SharedArrayBuffer apps.
Nightly Rust + build-std is unstable Medium Medium Pin to a known-good nightly. Revisit when wasm-threads stabilizes.
Web Worker spawn latency Low Low Spawn workers eagerly at runtime init, not per-actor.
Browser compatibility gaps Low Medium Target Chrome/Firefox/Safari latest. All support SharedArrayBuffer since 2021.