Skip to content

Add semantic machine testing and causal runtime probes - #85

Merged
SandroMaglione merged 4 commits into
mainfrom
codex/machine-test-invariants
Aug 10, 2026
Merged

Add semantic machine testing and causal runtime probes#85
SandroMaglione merged 4 commits into
mainfrom
codex/machine-test-invariants

Conversation

@SandroMaglione

Copy link
Copy Markdown
Member

Summary

  • add reusable state, step, and trace invariants for planner traces
  • add bounded breadth-first exploration with shortest witnesses, explicit truncation frontiers, and fail-closed reachability assertions
  • add testing-only causal runtime probes with acknowledged sendAndAwait delivery while keeping production MachineRef.send unchanged
  • exercise the testing APIs in the media-player and platformer examples

Changeset

  • Added or updated for a library or package-metadata change
  • Not required because this PR does not change src/ or package.json

Validation

  • pnpm check
  • Relevant example checks, when examples changed
  • Reviewed the automated type-performance report, when the public TypeScript API or inference changed
  • Reviewed the automated runtime-performance report, when runtime behavior changed

Additional local validation:

  • pnpm perf:types
  • pnpm perf:runtime
  • pnpm check in examples/playground
  • pnpm check in examples/platformer

The runtime implementation has generic-versus-compiled differential coverage. Probe tests cover ignored and targetless events, value changes, reentry, raised-event macrosteps, invoke startup, interrupted waiters, stopped references, unsupported references, and processing failures.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Type performance

Measured with TypeScript 6.0.3 and skipLibCheck=true.

Scenario Base PR Difference
Effect only 55 55 0 (0.0%)
Import effect-machine 55 55 0 (0.0%)
Machine.defineStates (3 states) 2,965 2,965 0 (0.0%)
Machine.make (3 states, 2 events) 8,715 8,715 0 (0.0%)
machine.handle (3 states, 2 transitions) 23,492 23,492 0 (0.0%)
machine.handle (depth 8) 117,075 117,075 0 (0.0%)
machine.handle (depth 12) 129,713 129,713 0 (0.0%)
machine.handle (depth 16) 145,055 145,055 0 (0.0%)
machine.handle (depth 24) 183,851 183,851 0 (0.0%)
machine.handle (wide depth 16) 214,189 214,189 0 (0.0%)
machine.handle (parallel/history/choice) 132,667 132,667 0 (0.0%)
machine.handle (4 successive calls) 128,674 128,674 0 (0.0%)
machine exact input/output/error/services 110,584 110,584 0 (0.0%)
execution adapter readiness 127,854 127,854 0 (0.0%)

Marginal instantiations are measured against the matching setup without that API call:

Scenario Base PR Difference
Import effect-machine 0 0 0
Machine.defineStates (3 states) 2,910 2,910 0 (0.0%)
Machine.make (3 states, 2 events) 5,742 5,742 0 (0.0%)
machine.handle (3 states, 2 transitions) 14,777 14,777 0 (0.0%)
machine.handle (depth 8) 109,601 109,601 0 (0.0%)
machine.handle (depth 12) 121,039 121,039 0 (0.0%)
machine.handle (depth 16) 135,181 135,181 0 (0.0%)
machine.handle (depth 24) 171,577 171,577 0 (0.0%)
machine.handle (wide depth 16) 202,224 202,224 0 (0.0%)
machine.handle (parallel/history/choice) 114,331 114,331 0 (0.0%)
machine.handle (4 successive calls) 113,703 113,703 0 (0.0%)
machine exact input/output/error/services 100,670 100,670 0 (0.0%)
execution adapter readiness 102,092 102,092 0 (0.0%)
Check times (informational)
Scenario Base PR
Effect only 0.03s 0.03s
Import effect-machine 0.04s 0.03s
Machine.defineStates (3 states) 0.11s 0.10s
Machine.make (3 states, 2 events) 0.17s 0.16s
machine.handle (3 states, 2 transitions) 0.23s 0.22s
machine.handle (depth 8) 0.51s 0.52s
machine.handle (depth 12) 0.57s 0.57s
machine.handle (depth 16) 0.63s 0.60s
machine.handle (depth 24) 0.72s 0.70s
machine.handle (wide depth 16) 0.78s 0.77s
machine.handle (parallel/history/choice) 0.60s 0.63s
machine.handle (4 successive calls) 0.60s 0.59s
machine exact input/output/error/services 0.51s 0.50s
execution adapter readiness 0.58s 0.62s

Type instantiations are the comparison metric. Check time varies with runner load and is informational only.

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on AMD EPYC 7763 64-Core Processor with Node v24.18.0.

Pull request baseline

Scenario Effect Machine XState 5 XState 6 alpha
Plan counter transitions 131,858 transitions/s 129,858 transitions/s 12,987 transitions/s
Drain burst with terminal fence 503,917 increments/s 386,648 increments/s 187,202 increments/s
Drain burst with a change observer 465,160 increments/s 383,758 increments/s 186,985 increments/s
Lookup and send to one child 398,411 increments/s 382,107 increments/s 180,186 increments/s
Start and stop a machine 170,329 machines/s 181,455 machines/s 137,306 machines/s
Start and stop a parent with one child 31,687 families/s 67,627 families/s 40,117 families/s
Plan transitions through a compound state 117,707 transitions/s
Plan transitions through parallel regions 90,722 transitions/s
Drain burst through a compound state 495,108 events/s 341,647 events/s 185,189 events/s
Drain burst through two parallel regions 463,088 events/s 259,940 events/s 140,804 events/s
Drain a compound-state burst with a change observer 453,725 events/s

Effect runtime reference points

Scenario Effect Machine Effect runtime primitives
Start and stop a raw generic process 16,366 processes/s
Start and stop a raw compiled process 66,498 processes/s
Start and interrupt a suspended fiber 163,908 fibers/s
Start and stop a queue worker 115,260 workers/s
Start and stop an actor shell 106,078 actors/s
Start and stop two actor shells 64,562 families/s
Update an owner-only mutable snapshot 316,856,781 updates/s
Update a synchronized snapshot 1,524,228 updates/s
Create, resolve, and await a terminal latch 1,420,132 latches/s
Memory profile Effect Machine XState 5 XState 6 alpha Effect runtime primitives
Idle machine 1.5 KiB 3.8 KiB 2.2 KiB
Raw generic managed process 12.7 KiB
Raw compiled process 2.8 KiB
Two independent idle machines 3.0 KiB 7.3 KiB 3.9 KiB
Idle parent with one child 4.8 KiB 5.5 KiB 4.0 KiB
Parent with observed child registry 9.0 KiB
Parent with observed invoked child snapshots 5.0 KiB
Suspended Effect fiber 0.6 KiB
Effect queue with waiting fiber 2.8 KiB
Effect mailbox actor shell 3.2 KiB
Two Effect actor shells 6.8 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 131,098 transitions/s 1.8% MAD 131,858 transitions/s 0.4% MAD +0.6%
Drain burst with terminal fence 521,974 increments/s 4.3% MAD 503,917 increments/s 1.2% MAD -3.5%
Drain burst with a change observer 481,440 increments/s 4.2% MAD 465,160 increments/s 1.4% MAD -3.4%
Lookup and send to one child 408,722 increments/s 4.1% MAD 398,411 increments/s 0.0% MAD -2.5%
Start and stop a machine 167,196 machines/s 0.3% MAD 170,329 machines/s 0.2% MAD +1.9%
Start and stop a parent with one child 32,997 families/s 4.2% MAD 31,687 families/s 1.1% MAD -4.0%
Plan transitions through a compound state 119,432 transitions/s 0.5% MAD 117,707 transitions/s 0.3% MAD -1.4%
Plan transitions through parallel regions 91,553 transitions/s 1.0% MAD 90,722 transitions/s 0.8% MAD -0.9%
Drain burst through a compound state 513,880 events/s 3.7% MAD 495,108 events/s 2.4% MAD -3.7%
Drain burst through two parallel regions 475,440 events/s 1.9% MAD 463,088 events/s 1.3% MAD -2.6%
Drain a compound-state burst with a change observer 464,787 events/s 2.9% MAD 453,725 events/s 2.3% MAD -2.4%
Idle machine heap per unit 1.5 KiB 0.2% MAD 1.5 KiB 0.1% MAD +0.5%
Raw generic managed process heap per unit 12.1 KiB 0.0% MAD 12.7 KiB 0.0% MAD +4.7%
Raw compiled process heap per unit 2.6 KiB 0.0% MAD 2.8 KiB 0.0% MAD +8.1%
Two independent idle machines heap per unit 2.9 KiB 0.0% MAD 3.0 KiB 0.0% MAD +0.4%
Idle parent with one child heap per unit 4.8 KiB 0.0% MAD 4.8 KiB 0.0% MAD +0.4%
Parent with observed child registry heap per unit 8.9 KiB 0.0% MAD 9.0 KiB 0.0% MAD +0.2%
Parent with observed invoked child snapshots heap per unit 5.0 KiB 0.0% MAD 5.0 KiB 0.0% MAD -0.0%

Effect runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 17,632 processes/s 2.1% MAD 16,366 processes/s 0.9% MAD -7.2%
Start and stop a raw compiled process 68,269 processes/s 0.3% MAD 66,498 processes/s 1.6% MAD -2.6%
Start and interrupt a suspended fiber 164,718 fibers/s 0.8% MAD 163,908 fibers/s 0.8% MAD -0.5%
Start and stop a queue worker 114,338 workers/s 0.2% MAD 115,260 workers/s 0.9% MAD +0.8%
Start and stop an actor shell 104,965 actors/s 0.2% MAD 106,078 actors/s 1.1% MAD +1.1%
Start and stop two actor shells 65,364 families/s 1.4% MAD 64,562 families/s 3.1% MAD -1.2%
Update an owner-only mutable snapshot 316,856,781 updates/s 0.0% MAD 316,856,781 updates/s 0.0% MAD 0.0%
Update a synchronized snapshot 1,543,436 updates/s 1.2% MAD 1,524,228 updates/s 1.6% MAD -1.2%
Create, resolve, and await a terminal latch 1,442,044 latches/s 1.4% MAD 1,420,132 latches/s 2.2% MAD -1.5%
Versions and interpretation
  • Effect Machine: 0.4.0
  • XState 5: 5.32.5
  • XState 6 alpha: 6.0.0-alpha.31
  • Effect runtime primitives: 4.0.0-beta.107

Higher throughput is better; lower heap is better. Variability is the median absolute deviation across independent processes, relative to their median. Runtime measurements on shared GitHub-hosted hardware remain informational, so small differences should be confirmed across multiple workflow runs.

@SandroMaglione
SandroMaglione marked this pull request as ready for review August 10, 2026 15:59
@SandroMaglione
SandroMaglione merged commit 0dbb538 into main Aug 10, 2026
9 checks passed
@SandroMaglione
SandroMaglione deleted the codex/machine-test-invariants branch August 10, 2026 16:02
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