Skip to content

Add bounded microstep traces and inspection - #42

Merged
JovaniPink merged 1 commit into
masterfrom
bounded-microstep-traces
Aug 24, 2026
Merged

Add bounded microstep traces and inspection#42
JovaniPink merged 1 commit into
masterfrom
bounded-microstep-traces

Conversation

@JovaniPink

@JovaniPink JovaniPink commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

Add bounded run-to-completion execution, immutable typed microstep traces, and fail-open inspection callbacks for machine runtimes.

Rationale

Stable XState v5 exposes public microstep utilities and a maxIterations guard for non-settling machines. Python already had a W3C-style macrostep loop, but callers could only observe the final snapshot and an eventless or raised-event cycle could run without a configured bound.

This PR keeps transition calculation pure. It records portable summaries at each settled microstep, resolves public snapshots at the machine boundary, and leaves action execution with interpreters and actors.

Scope

  • Add frozen TransitionTrace, MicrostepTrace, and MacrostepTrace records with defaulted generics.
  • Add get_microsteps(machine, snapshot, event) and get_initial_microsteps(machine).
  • Record external, eventless, raised, and ignored internal events in execution order.
  • Keep only each microstep's actions on its intermediate snapshot while preserving all ordered macrostep actions on Machine.transition results.
  • Add MachineOptionsConfig and support JSON options.maxIterations.
  • Add Machine(..., max_iterations=N) with non-None keyword precedence.
  • Reject Boolean, negative, and non-integer limits with InvalidConfigError.
  • Raise InfiniteLoopError before the first enabled microstep over the limit.
  • Keep interpreter snapshots transactional when pure execution fails.
  • Add typed inspect callbacks to sync and async interpreters and machine-backed actors.
  • Invoke inspectors after snapshot installation and before actions and ordinary subscribers.
  • Warn and continue when an inspector raises.
  • Document the bounded execution and local inspection APIs.

Trace boundary

Transition summaries expose only event type, source ID, and ordered target IDs. Public trace records do not expose internal Transition objects, a mutable configuration set, or the internal queue. Intermediate state containers retain the existing immutable public configuration and action boundaries.

Non-scope

  • Promise, callback, observable, actor-system topology, or remote inspection.
  • The @statelyai/inspect wire protocol.
  • Explicit runtime effect descriptors or durable execution.
  • Snapshot schema versioning or migrations.
  • Runtime schema validation.
  • Version changes, publication, or new conformance claims.

Validation

Local Python 3.14:

  • poetry run python -m pytest tests/ --ignore=tests/test_scxml.py: 480 passed.
  • poetry run python -m pytest tests/test_scxml.py: 57 passed.
  • poetry run mypy src/xstate/: passed.
  • poetry run mypy --strict src/xstate/algorithm.py: passed.
  • Positive and negative strict-mypy consumer fixtures: passed.
  • Ruff format and lint checks: passed.
  • poetry check --lock: passed.
  • poetry build: passed.
  • poetry run python scripts/validate_distribution.py: installed-wheel smoke passed.

Hosted exact head 1b1106d9385d99af61d7bdbecb6fa84b069b3e73:

  • Python 3.13 test job: passed.
  • Python 3.14 test job: passed.
  • SCXML smoke job: passed.
  • Python 3.14 code-quality job: passed.

Risks and rollback

The highest-risk area is the macrostep loop because tracing and the iteration counter observe every enabled microstep. Regression coverage locks FIFO internal events, ignored-event records, action accumulation, limit timing, final output, and existing SCXML behavior. Inspectors are fail-open and do not participate in transition calculation.

There is additional allocation when a macrostep captures intermediate immutable records. No persisted format or external dependency changes. Rollback is a revert of this PR after reverting or retargeting PR 3.

Review focus

  • Limit accounting immediately before enabled microstep execution.
  • Empty trace records for ignored external and internal events.
  • Per-microstep context, history, output, and action capture.
  • Inspector ordering relative to state installation, effects, and subscribers.
  • Generic inference for trace helpers and callbacks.

Stack and merge order

This is PR 2 of 3. PR 1 has merged, so this PR now targets master. Merge it before actor-ref-boundary.

@JovaniPink
JovaniPink changed the base branch from v5-descriptor-target-parity to master August 24, 2026 18:14
@JovaniPink
JovaniPink marked this pull request as ready for review August 24, 2026 18:15
@JovaniPink
JovaniPink merged commit 73878e2 into master Aug 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant