swactor/docs/development_history/in-browser/FEATURE_PARITY.md

76 lines
3.7 KiB
Markdown
Raw Normal View History

# Feature Parity — Development History
> Stage 4 of the in-browser swactor runtime. Enables swactor-std extensions
> (naming, monitoring, groups) and core actor watching in the wasm crate.
---
## Changes
### swactor-std wasm compilation
- Added `wasm` feature to `crates/std/Cargo.toml` (forwards to `swactor/wasm`)
- Changed swactor dependency to `default-features = false`, forwarding `getrandom`
feature when active (`getrandom = ["dep:getrandom", "swactor/getrandom"]`)
- Cfg-gated `getrandom::getrandom()` call in `router.rs` `RoutingStrategy::Random`
— falls back to round-robin when `getrandom` feature is disabled (wasm mode)
### RuntimeNaming: register_name
- Added `register_name(name, addr)` method to `RuntimeNaming` trait and impl
— allows registering a name for an already-spawned actor from outside the runtime
— complements existing `spawn_named` (which spawns + registers atomically)
### Core watching fix: StopSignal death notifications
- Fixed gap in `worker.rs` tick_all: externally-stopped actors (via `rt.stop_actor()`)
were not added to the `deaths` list, so core WatchRegistry (phase 5b) never fired
for them. Added `deaths.push((addr, ExitReason::Stopped))` when StopSignal is
intercepted (line 737). All 140 existing native tests continue to pass.
### WasmRuntime: StdExtension + new APIs
- `WasmRuntime::new()` now installs `StdExtension` automatically
- New inbox type: `WasmInboxString` for receiving string notifications
- **Naming API**: `register_name`, `where_is`, `unregister_name`, `registered_names`
- **Groups API**: `join_group`, `leave_group`, `publish_to_group_u32`,
`group_member_count`, `group_names`
- **Stats API**: `total_messages`, `total_panics` (returned as f64 for JS compat)
- New demo actors:
- `Sentinel` — watches a target via `ctx.watch()`, reports death to string inbox
- `GroupMember` — joins a group on start, forwards u32 messages to report inbox
### Design Decisions
| # | Decision | Rationale |
|---|----------|-----------|
| 1 | StdExtension always installed | Browser runtime should have full naming/groups by default |
| 2 | Stats as f64, not u64 | wasm-bindgen maps u64 to BigInt which JSON.stringify rejects |
| 3 | Sentinel actor for watching | Demonstrates core watching from JS without exposing Watch API directly |
| 4 | register_name on RuntimeNaming | Needed for post-spawn registration from JS (no actor context available) |
| 5 | Round-robin fallback for Random routing | wasm mode disables getrandom; graceful degradation preferred |
## Test Coverage
22 new assertions across 10 new test scenarios (30 total, from 10):
| Test | Scenario |
|------|----------|
| naming — register_name and where_is | Register name, resolve, verify not-found returns undefined |
| naming — unregister_name | Unregister returns previous addr, name no longer resolves |
| naming — registered_names | Lists all registered names as CSV |
| naming — duplicate name rejected | Second registration with same name fails |
| groups — join_group and publish_to_group_u32 | Two members receive broadcast message |
| groups — leave_group | Member count decreases after leave |
| groups — group_names | Lists all active group names |
| watching — sentinel reports actor death | Stop target → sentinel receives death notification |
| stats — total_messages | Counts processed messages across workers |
| stats — total_panics starts at zero | Fresh runtime has zero panics |
## Verification
- `cargo test -p swactor -p swactor-std` — 157 native tests pass (no regressions)
- `cargo build --target wasm32-unknown-unknown -p wasm` — compiles
- `wasm-pack build --target nodejs` in `crates/wasm/` — builds pkg/
- `node test.mjs` in `crates/wasm/` — 30/30 tests pass