Skip to content

Add prepared machine lifecycle and bound invocation typing - #115

Merged
SandroMaglione merged 1 commit into
mainfrom
codex/prepared-machine-lifecycle
Aug 15, 2026
Merged

Add prepared machine lifecycle and bound invocation typing#115
SandroMaglione merged 1 commit into
mainfrom
codex/prepared-machine-lifecycle

Conversation

@SandroMaglione

Copy link
Copy Markdown
Member

Summary

  • add Machine.prepare so emission and snapshot streams can be composed before initialization, while preserving the direct Machine.start hot path
  • make prepared.start one-shot and share startup identity/results across concurrent and repeated evaluation
  • let AtomMachine.emissions subscribe before initial entry when it activates a fresh machine
  • add definition.invoke(...) for exact public self and parentEvents typing, while keeping standalone Machine.invoke(...) owner-independent
  • document the lifecycle and invocation APIs and cover generic/compiled runtimes, schema failures, AtomMachine, packed declarations, and parent delivery

Changeset

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

Minor changeset: .changeset/calm-machines-prepare.md.

Validation

  • pnpm check
  • Relevant example checks, when examples changed
  • Automated type-performance measurement passed or was not required
  • Automated runtime- and memory-performance measurement passed or was not required

Also ran pnpm check in examples/pokemon, examples/playground, and examples/platformer. Local runtime comparison retained the base memory slopes for the direct compiled path; the PR workflows remain authoritative for base-versus-PR runtime and previous-version compatibility.

@github-actions

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) 3,039 3,039 0 (0.0%)
Machine.make (3 states, 2 events) 13,199 13,199 0 (0.0%)
machine.handle (3 states, 2 transitions) 30,391 30,443 +52 (+0.2%)
Machine.invoke (state-dependent Effect) 70,267 70,236 -31 (-0.0%)
machine.handle (depth 24) 187,535 188,212 +677 (+0.4%)
machine.handle (wide depth 16) 219,937 220,710 +773 (+0.4%)
machine.handle (parallel/history/choice) 127,424 128,069 +645 (+0.5%)
machine.handle (4 successive calls) 135,105 135,838 +733 (+0.5%)
machine exact input/output/error/services 109,347 109,952 +605 (+0.6%)
execution adapter readiness 121,052 121,683 +631 (+0.5%)

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,984 2,984 0 (0.0%)
Machine.make (3 states, 2 events) 10,152 10,152 0 (0.0%)
machine.handle (3 states, 2 transitions) 17,192 17,244 +52 (+0.3%)
Machine.invoke (state-dependent Effect) 59,234 59,203 -31 (-0.1%)
machine.handle (depth 24) 167,466 168,143 +677 (+0.4%)
machine.handle (wide depth 16) 200,929 201,702 +773 (+0.4%)
machine.handle (parallel/history/choice) 101,770 102,415 +645 (+0.6%)
machine.handle (4 successive calls) 113,854 114,587 +733 (+0.6%)
machine exact input/output/error/services 92,816 93,421 +605 (+0.7%)
execution adapter readiness 86,974 87,555 +581 (+0.7%)
Check times (informational)
Scenario Base PR
Effect only 0.03s 0.03s
Import effect-machine 0.03s 0.03s
Machine.defineStates (3 states) 0.10s 0.10s
Machine.make (3 states, 2 events) 0.17s 0.16s
machine.handle (3 states, 2 transitions) 0.25s 0.25s
Machine.invoke (state-dependent Effect) 0.37s 0.39s
machine.handle (depth 24) 0.66s 0.65s
machine.handle (wide depth 16) 0.69s 0.70s
machine.handle (parallel/history/choice) 0.54s 0.54s
machine.handle (4 successive calls) 0.56s 0.56s
machine exact input/output/error/services 0.49s 0.48s
execution adapter readiness 0.50s 0.49s

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

@github-actions

Copy link
Copy Markdown
Contributor

Runtime performance

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

Pull request baseline

Scenario Effect Machine
Plan counter transitions 120,950 transitions/s
Drain burst with terminal fence 376,940 increments/s
Drain burst with a change observer 350,629 increments/s
Lookup and send to one child 309,684 increments/s
Start and stop a machine 150,557 machines/s
Start and stop a parent with one child 30,883 families/s
Plan transitions through a compound state 107,788 transitions/s
Plan transitions through parallel regions 84,117 transitions/s
Drain burst through a compound state 371,458 events/s
Drain burst through two parallel regions 345,582 events/s
Drain a compound-state burst with a change observer 344,342 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 15,444 processes/s
Start and stop a raw compiled process 62,617 processes/s
Memory profile Effect Machine
Idle machine 1.7 KiB
Raw generic managed process 13.7 KiB
Raw compiled process 2.9 KiB
Two independent idle machines 3.3 KiB
Idle parent with one child 5.2 KiB
Parent with observed child registry 9.4 KiB
Parent with observed invoked child snapshots 5.6 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 118,679 transitions/s 2.6% MAD 120,950 transitions/s 0.6% MAD +1.9%
Drain burst with terminal fence 380,313 increments/s 1.2% MAD 376,940 increments/s 1.7% MAD -0.9%
Drain burst with a change observer 350,740 increments/s 1.4% MAD 350,629 increments/s 1.0% MAD -0.0%
Lookup and send to one child 308,019 increments/s 2.3% MAD 309,684 increments/s 1.0% MAD +0.5%
Start and stop a machine 148,302 machines/s 2.5% MAD 150,557 machines/s 0.7% MAD +1.5%
Start and stop a parent with one child 30,600 families/s 1.9% MAD 30,883 families/s 3.9% MAD +0.9%
Plan transitions through a compound state 107,678 transitions/s 2.1% MAD 107,788 transitions/s 0.3% MAD +0.1%
Plan transitions through parallel regions 83,351 transitions/s 0.1% MAD 84,117 transitions/s 0.7% MAD +0.9%
Drain burst through a compound state 370,415 events/s 0.2% MAD 371,458 events/s 0.3% MAD +0.3%
Drain burst through two parallel regions 341,043 events/s 1.6% MAD 345,582 events/s 0.3% MAD +1.3%
Drain a compound-state burst with a change observer 345,371 events/s 0.5% MAD 344,342 events/s 0.4% MAD -0.3%
Idle machine heap per unit 1.7 KiB 0.1% MAD 1.7 KiB 0.1% MAD +0.6%
Raw generic managed process heap per unit 13.6 KiB 0.0% MAD 13.7 KiB 0.0% MAD +0.6%
Raw compiled process heap per unit 2.9 KiB 0.1% MAD 2.9 KiB 0.0% MAD +0.3%
Two independent idle machines heap per unit 3.3 KiB 0.0% MAD 3.3 KiB 0.0% MAD -0.2%
Idle parent with one child heap per unit 5.2 KiB 0.0% MAD 5.2 KiB 0.0% MAD +0.3%
Parent with observed child registry heap per unit 9.4 KiB 0.0% MAD 9.4 KiB 0.0% MAD +0.2%
Parent with observed invoked child snapshots heap per unit 5.6 KiB 0.0% MAD 5.6 KiB 0.1% MAD +0.3%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 15,741 processes/s 1.3% MAD 15,444 processes/s 3.4% MAD -1.9%
Start and stop a raw compiled process 61,920 processes/s 0.7% MAD 62,617 processes/s 1.3% MAD +1.1%

Regression guard

No large, noise-adjusted throughput or heap regressions detected.

Versions and interpretation
  • Effect Machine: 0.10.0

Higher throughput is better; lower heap is better. Variability is the median absolute deviation across independent processes, relative to their median. Small differences on shared GitHub-hosted hardware remain informational; the required guard rejects only large changes beyond the measured noise allowance.

@SandroMaglione
SandroMaglione merged commit 2a84cd2 into main Aug 15, 2026
13 checks passed
@SandroMaglione
SandroMaglione deleted the codex/prepared-machine-lifecycle branch August 15, 2026 16:45
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