scxml 0.2.0

W3C SCXML statechart library — parse, validate, export, and simulate Harel statecharts. Framework-agnostic, WASM-ready, rkyv zero-copy.
Documentation
# scxml Agent Guide

This file is the canonical, repo-shared instruction source for AI coding agents and automation helpers working in this repository.

Tool-specific files should stay thin and point back here:

- `.claude/CLAUDE.md`
- `.github/.copilot-instructions.md`

If project guidance changes, update this file first and only keep tool-specific deltas in the adapters.

## Overview

`scxml` is a W3C SCXML statechart library for Rust. It parses, validates, visualizes, diffs, exports, and simulates Harel statecharts.

It is **not** a runtime executor. This crate is the cold-path document model that sits between human-editable workflow definitions and downstream native runtime types.

Project goals:

- Strong SCXML import/export and round-trip fidelity
- Validation and review tooling for workflow documents
- Clean browser/WASM story for client-side inspection
- Publishable, platform-agnostic Rust crate with zero runtime-framework coupling

## Core Boundaries

Keep these boundaries intact:

- This crate owns parsing, validation, export, diffing, flattening, statistics, sanitization, and lightweight simulation.
- This crate does not execute production workflows at hot-path transition time.
- Guards are named predicates, not embedded logic.
- Actions are inert descriptors, not executable code.
- Platform-specific integration belongs downstream, not in this crate.

Two-speed architecture:

- Cold path: parse, validate, simulate, export, diff, review
- Hot path: downstream code compiles validated statecharts into native runtime types

## Repository Map

Primary areas:

- `src/`: public library code
- `src/model/`: statechart data model
- `src/parse/`: SCXML XML and JSON parsing
- `src/validate/`: structural and liveness validation
- `src/export/`: XML, DOT, Mermaid, JSON exporters
- `src/flatten.rs`: flat graph projection helpers
- `src/diff.rs`: structural diff support
- `src/simulate.rs`: lightweight test simulator
- `src/wasm.rs`: wasm-bindgen surface for browser/demo consumers
- `tests/`: roundtrip, invariants, examples, XState, W3C subset
- `examples/`: checked-in SCXML examples and representative XState JSON counterparts
- `benches/`: criterion performance benchmarks
- `demo/`: browser demo using the generated WASM package and synced example files
- `scripts/build-wasm-package.sh`: canonical WASM build and demo sync entry point

## Coding Rules

- Rust edition: `2024`
- MSRV: `1.87`
- Use `thiserror`, never `anyhow`, in library code.
- Use `compact_str::CompactString` for model identifiers.
- Error payload fields may use `String` where required for compatibility.
- No embedded scripting engine. Never evaluate `<script>`, `<invoke>`, `<if>`, `<foreach>`, or `<cancel>`.
- Keep public APIs semver-safe and additive where practical.
- No lint suppressions. Do not add `_unused` bindings or `#[allow(...)]` shortcuts.
- Keep changes minimal and targeted; do not reformat unrelated code.

## SCXML Semantics To Preserve

- Structural validation must recurse from top-level states; do not validate nested states as if they were root nodes.
- Liveness analysis must respect inherited transitions.
- `Transition` supports both fluent `with_*` methods and mutable `set_*` methods.
- `delay` values use ISO 8601 duration syntax.
- `gnomes:quorum` is a Gnomes extension and must remain additive to standard SCXML.
- `diff::diff()` is semantic by state ID, not by array position.
- `xstate::types` stays `pub(crate)`; user-facing XState integration goes through parse/export functions.

## Security Rules

When input is untrusted, prefer `parse_untrusted()` over raw XML parsing.

Security expectations:

- Reject `<!DOCTYPE>` and `<!ENTITY>` in untrusted parsing flows.
- Enforce identifier validation and configured input limits.
- Treat the `Statechart` as inert data only.
- Preserve escaping guarantees in XML, DOT, and Mermaid exporters.

## Performance And Benchmark Story

The benchmark story should stay coherent, honest, and based on checked-in fixtures.

Current benchmark framing:

- small realistic example: `examples/document_lifecycle.scxml` with 5 states
- synthetic scaling chain sizes: `10`, `50`, `500`
- `rkyv` benches should use the same size matrix when comparisons are shown side-by-side

If benchmarks change materially, keep these aligned together:

- `benches/statechart.rs`
- `benches/rkyv_bench.rs`
- `README.md`
- any marketing copy or demo copy that references measured numbers

## Examples And Interop

- Not every checked-in SCXML example needs an XState counterpart.
- Keep XState JSON files for representative interop coverage, not for box-ticking parity.
- Prefer realistic examples over toy workflows when they clarify hierarchy, parallelism, approval flow, or review semantics.

## Demo Workflow

The browser demo is part of the repo story, not a throwaway extra.

Important behavior:

- The demo loads synced copies from `demo/examples/`.
- The canonical build path is `./scripts/build-wasm-package.sh --scope gnomes --sync-demo`.
- The demo showcases graph, JSON, DOT, Mermaid, semantic diff, and simulation.
- The loaded example becomes the review baseline.
- `Restore Baseline` resets editor contents to that loaded example.
- `Reset Simulation` resets only runtime simulation state and history.

If example files or WASM exports change, keep the demo and demo README consistent.

## Testing Expectations

Run the narrowest relevant checks first, then broader ones when warranted.

Common commands:

```bash
cargo test
cargo test --all-features
cargo test --test examples
cargo test --test w3c_subset
cargo clippy --all-features
cargo bench --bench statechart
cargo bench --bench rkyv_bench --features rkyv
./scripts/build-wasm-package.sh --scope gnomes --sync-demo
```

When editing examples, demo behavior, README performance claims, or WASM bindings, validate the affected surface directly.

## Documentation Rules

- Keep README claims accurate to the measured benchmark story.
- Keep demo documentation synchronized with actual demo behavior.
- Do not leave stale counts, stale example inventories, or obsolete build steps in instruction files.
- Prefer one canonical explanation over duplicated, drifting copies.

## Instruction File Policy

This repository intentionally keeps agent instruction files tracked.

Policy:

- `AGENTS.md` is the canonical project guidance.
- `.claude/CLAUDE.md` is a thin adapter for Claude-compatible tooling.
- `.github/.copilot-instructions.md` is a thin adapter for Copilot-compatible tooling.
- Do not add these files to `.gitignore` unless the project explicitly decides to stop shipping agent guidance.
- Do not maintain multiple full copies of the same project instructions.

## Default Agent Behavior

When making changes in this repo:

- preserve the crate's role as a document model rather than a runtime engine
- prefer precise, minimal edits
- validate behavior after changes
- keep benchmarks, examples, demo, and docs narratively aligned
- avoid speculative features that blur the crate boundary

License context: MIT OR Apache-2.0.