# Developer Experience
This document captures the **developer experience (DX)** goals for `ready-active-safe`:
make the crate **easy to adopt**, **hard to misuse**, and **safe to run in production**.
It is both a set of principles and a checklist for future changes.
---
## DX North Star
Within 15 minutes, a new user should be able to:
1. Add the dependency (including a `no_std` path if needed)
2. Model modes/events/commands in a single file
3. Write `Machine::on_event` as a plain `match`
4. Run a tiny loop that feeds events and executes commands (manual or via `runtime::Runner`)
5. Add a policy and test denied transitions with plain assertions
If onboarding takes longer, something is wrong with either:
the API surface, the docs/examples, or the mental model.
---
## Research Inputs (What We Learn From)
We align with established Rust ecosystem guidance:
- Rust API Guidelines: https://rust-lang.github.io/api-guidelines/
- Rustdoc / doctest patterns: https://doc.rust-lang.org/rustdoc/
- Cargo feature flag behavior: https://doc.rust-lang.org/cargo/reference/features.html
And we continuously compare against existing state machine crates listed in `landscape.md`.
Cross-language interface patterns and ergonomics notes live in `API_ERGONOMICS.md`.
---
## Principles
### 1) Copy/Paste First
Examples are part of the API. The crate must have:
- A minimal “3 modes” example
- A recovery example (Safe → Ready)
- A “real” domain example (e.g., XR session lifecycle)
- A replay example demonstrating determinism
All examples should build and be runnable as-is.
### 2) Small Kernel, Composable Adapters
The core should stay tiny:
- `Machine`, `Decision`, `ModeChange`, `Policy`, `LifecycleError`
Everything else is optional:
- Runtime loops, timers, journaling, tracing, serialization, etc.
This keeps the crate useful in embedded/no_std and avoids framework lock-in.
### 3) Make The “Right Way” The Easy Way
The crate should “bias” users into:
- Returning decisions as data, not performing effects
- Keeping transitions explicit
- Treating Safe/recovery paths as normal lifecycle behavior
### 4) Commit To Clear Semantics
Ambiguity kills production use. We must explicitly define:
- Whether commands are dispatched when a transition is denied by policy
- Whether command ordering is guaranteed (it should be)
- How replay relates to determinism (same inputs -> same decision outputs)
If semantics aren’t written down, users invent them.
---
## Ergonomics Checklist (API)
Keep the API ergonomic without growing it into a framework:
- Avoid forcing `Clone` on mode/event/command types
- Provide “consume-self” accessors for runtimes (move out mode change / commands)
- Keep trait bounds off the core traits unless absolutely necessary
- Prefer data-returning constructors over builder macros
- Keep naming consistent: `Mode`, `Event`, `Command`, `Decision`, `Policy`
---
## Documentation Checklist
Documentation is a product feature:
- Every public item has a doc comment and a runnable example when meaningful
- The crate root (`lib.rs`) should explain the philosophy and show the smallest working example
- Concept docs live in `docs/` and are linked from `README.md`
- Examples are cross-linked from the user guide
---
## DX Backlog (High-Value Improvements)
Prioritize changes that reduce “first runtime” friction and make the crate feel
pleasant to work with (Rails-style “pit of success”):
- Maintain `prelude::*` as the “one import” path (including feature types when enabled)
- Maintain the cookbook-style guide (`docs/COOKBOOK.md`) for common patterns:
- `Runner` + dispatch
- `Runner` + `Policy` (denial handling)
- `Runner` + `InMemoryJournal` (audit + replay)
- `ManualClock` + `Deadline` (timeouts composed via events)
- Add integration guidance and examples for logging (`tracing`) and serialization (`serde`) as optional adapters
- Add an async example that wraps the synchronous `Runner` inside a tokio task/channel loop (no async runtime in core)
- Publish a small “starter template” (e.g., `cargo-generate`) for a new lifecycle project
The goal is to remove friction without expanding into a general FSM framework.