Skip to content

Redesign state-owned invocation API - #110

Merged
SandroMaglione merged 3 commits into
mainfrom
codex/inline-invoke-api
Aug 15, 2026
Merged

Redesign state-owned invocation API#110
SandroMaglione merged 3 commits into
mainfrom
codex/inline-invoke-api

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Aug 15, 2026

Copy link
Copy Markdown
Member

Summary

  • replace Machine.invokeEffect, Machine.after, Machine.invokeMachine, and Machine.effect with one state-owned inline invocation model for effect, after, logic, and child sources
  • route typed onDone, onFailure, and onSnapshot outcomes through direct owning-state transitions, with source/initialization failures, defects, and interruption failing the machine
  • infer state-dependent Effect owner context, output, error, and service channels together without return annotations
  • enforce conditional lifecycle handlers, distinct logic lifecycle IDs and communication addresses, Logic-only spawning, and planner inspection support
  • retain indexed initialization and ordinary-event execution for invoking machines while routing private invocation lifecycle messages through the generic semantic planner
  • migrate documentation, examples, consumer/performance fixtures, runtime tests, and type-inference coverage

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 added for the pre-1.0 breaking API change.

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

Example checks passed for platformer, playground, and pokemon against the packed declarations. Local pnpm perf:types stayed within configured instantiation budgets, including a new state-dependent Machine.invoke scenario at 65,033 total / 57,838 marginal instantiations.

Local pnpm perf:runtime completed successfully. The authoritative five-process PR comparison reports no large noise-adjusted regressions. The previously failing parent/child start-stop scenario is now 7.1% faster than main, while its idle heap is 1.1% higher; the largest remaining observed heap difference is 5.7% for invoked-child snapshot observation, within the guard.

@SandroMaglione
SandroMaglione marked this pull request as ready for review August 15, 2026 04:14
@github-actions

github-actions Bot commented Aug 15, 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) 3,039 3,039 0 (0.0%)
Machine.make (3 states, 2 events) 9,192 9,192 0 (0.0%)
machine.handle (3 states, 2 transitions) 25,009 26,099 +1,090 (+4.4%)
Machine.invoke (state-dependent Effect) 65,033 new
machine.handle (depth 24) 179,772 183,210 +3,438 (+1.9%)
machine.handle (wide depth 16) 209,566 215,308 +5,742 (+2.7%)
machine.handle (parallel/history/choice) 120,540 123,089 +2,549 (+2.1%)
machine.handle (4 successive calls) 118,189 122,233 +4,044 (+3.4%)
machine exact input/output/error/services 94,055 95,364 +1,309 (+1.4%)
execution adapter readiness 112,064 116,727 +4,663 (+4.2%)

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) 6,145 6,145 0 (0.0%)
machine.handle (3 states, 2 transitions) 15,817 16,907 +1,090 (+6.9%)
Machine.invoke (state-dependent Effect) 57,838 new
machine.handle (depth 24) 163,541 166,979 +3,438 (+2.1%)
machine.handle (wide depth 16) 194,396 200,138 +5,742 (+3.0%)
machine.handle (parallel/history/choice) 98,780 101,329 +2,549 (+2.6%)
machine.handle (4 successive calls) 101,001 105,045 +4,044 (+4.0%)
machine exact input/output/error/services 82,932 84,241 +1,309 (+1.6%)
execution adapter readiness 83,431 86,687 +3,256 (+3.9%)
Check times (informational)
Scenario Base PR
Effect only 0.03s 0.03s
Import effect-machine 0.03s 0.03s
Machine.defineStates (3 states) 0.11s 0.11s
Machine.make (3 states, 2 events) 0.16s 0.16s
machine.handle (3 states, 2 transitions) 0.25s 0.26s
Machine.invoke (state-dependent Effect) 0.37s
machine.handle (depth 24) 0.73s 0.73s
machine.handle (wide depth 16) 0.74s 0.75s
machine.handle (parallel/history/choice) 0.57s 0.59s
machine.handle (4 successive calls) 0.53s 0.55s
machine exact input/output/error/services 0.46s 0.49s
execution adapter readiness 0.54s 0.52s

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

@github-actions

github-actions Bot commented Aug 15, 2026

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 136,192 transitions/s
Drain burst with terminal fence 519,738 increments/s
Drain burst with a change observer 475,832 increments/s
Lookup and send to one child 408,263 increments/s
Start and stop a machine 171,792 machines/s
Start and stop a parent with one child 35,470 families/s
Plan transitions through a compound state 121,372 transitions/s
Plan transitions through parallel regions 92,761 transitions/s
Drain burst through a compound state 463,424 events/s
Drain burst through two parallel regions 420,652 events/s
Drain a compound-state burst with a change observer 426,906 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 15,942 processes/s
Start and stop a raw compiled process 66,405 processes/s
Memory profile Effect Machine
Idle machine 1.5 KiB
Raw generic managed process 12.7 KiB
Raw compiled process 2.8 KiB
Two independent idle machines 3.0 KiB
Idle parent with one child 4.8 KiB
Parent with observed child registry 9.0 KiB
Parent with observed invoked child snapshots 5.3 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 137,501 transitions/s 0.9% MAD 136,192 transitions/s 0.9% MAD -1.0%
Drain burst with terminal fence 531,460 increments/s 0.8% MAD 519,738 increments/s 0.3% MAD -2.2%
Drain burst with a change observer 477,653 increments/s 0.4% MAD 475,832 increments/s 1.2% MAD -0.4%
Lookup and send to one child 427,371 increments/s 0.4% MAD 408,263 increments/s 1.1% MAD -4.5%
Start and stop a machine 170,329 machines/s 0.2% MAD 171,792 machines/s 0.7% MAD +0.9%
Start and stop a parent with one child 33,105 families/s 0.5% MAD 35,470 families/s 1.4% MAD +7.1%
Plan transitions through a compound state 122,977 transitions/s 1.3% MAD 121,372 transitions/s 1.3% MAD -1.3%
Plan transitions through parallel regions 94,350 transitions/s 0.7% MAD 92,761 transitions/s 0.5% MAD -1.7%
Drain burst through a compound state 455,889 events/s 0.4% MAD 463,424 events/s 1.2% MAD +1.7%
Drain burst through two parallel regions 416,746 events/s 0.2% MAD 420,652 events/s 0.7% MAD +0.9%
Drain a compound-state burst with a change observer 420,206 events/s 0.5% MAD 426,906 events/s 1.1% MAD +1.6%
Idle machine heap per unit 1.5 KiB 0.0% MAD 1.5 KiB 0.2% MAD +0.1%
Raw generic managed process heap per unit 12.7 KiB 0.0% MAD 12.7 KiB 0.0% MAD -0.0%
Raw compiled process heap per unit 2.8 KiB 0.4% MAD 2.8 KiB 0.1% MAD -0.4%
Two independent idle machines heap per unit 3.0 KiB 0.0% MAD 3.0 KiB 0.0% MAD -0.0%
Idle parent with one child heap per unit 4.8 KiB 0.0% MAD 4.8 KiB 0.1% MAD +1.1%
Parent with observed child registry heap per unit 9.0 KiB 0.0% MAD 9.0 KiB 0.0% MAD +0.6%
Parent with observed invoked child snapshots heap per unit 5.0 KiB 0.0% MAD 5.3 KiB 0.0% MAD +5.7%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 15,955 processes/s 1.0% MAD 15,942 processes/s 3.7% MAD -0.1%
Start and stop a raw compiled process 66,988 processes/s 0.5% MAD 66,405 processes/s 0.4% MAD -0.9%

Regression guard

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

Versions and interpretation
  • Effect Machine: 0.8.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 59580de into main Aug 15, 2026
13 checks passed
@SandroMaglione
SandroMaglione deleted the codex/inline-invoke-api branch August 15, 2026 08:05
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