ready-active-safe 0.1.3

Lifecycle engine for externally driven systems
Documentation
# 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.