Skip to content

Require factories for invoked Effects - #123

Merged
SandroMaglione merged 1 commit into
mainfrom
codex/factory-only-invoke-effects
Aug 16, 2026
Merged

Require factories for invoked Effects#123
SandroMaglione merged 1 commit into
mainfrom
codex/factory-only-invoke-effects

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Aug 16, 2026

Copy link
Copy Markdown
Member

Summary

  • require Machine.invoke Effect sources to be factories evaluated on state entry
  • remove direct-Effect overloads and preserve lifecycle output, error, and service inference from factory return types
  • migrate documentation, examples, tests, and consumer fixtures, with a TypeScript autocomplete regression test

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
  • Automated type-performance measurement passed or was not required
  • Automated runtime- and memory-performance measurement passed or was not required

Type instantiations improved for the affected Machine.invoke scenario. The runtime comparison detected no large, noise-adjusted throughput or heap regressions.

@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,443 30,443 0 (0.0%)
Machine.invoke (state-dependent Effect) 70,236 69,502 -734 (-1.0%)
machine.handle (depth 24) 188,212 188,193 -19 (-0.0%)
machine.handle (wide depth 16) 220,710 220,691 -19 (-0.0%)
machine.handle (parallel/history/choice) 128,069 128,050 -19 (-0.0%)
machine.handle (4 successive calls) 135,838 135,819 -19 (-0.0%)
machine exact input/output/error/services 109,952 109,933 -19 (-0.0%)
execution adapter readiness 121,683 120,876 -807 (-0.7%)

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,244 17,244 0 (0.0%)
Machine.invoke (state-dependent Effect) 59,203 58,469 -734 (-1.2%)
machine.handle (depth 24) 168,143 168,124 -19 (-0.0%)
machine.handle (wide depth 16) 201,702 201,683 -19 (-0.0%)
machine.handle (parallel/history/choice) 102,415 102,396 -19 (-0.0%)
machine.handle (4 successive calls) 114,587 114,568 -19 (-0.0%)
machine exact input/output/error/services 93,421 93,402 -19 (-0.0%)
execution adapter readiness 87,555 86,748 -807 (-0.9%)
Check times (informational)
Scenario Base PR
Effect only 0.02s 0.02s
Import effect-machine 0.02s 0.02s
Machine.defineStates (3 states) 0.07s 0.07s
Machine.make (3 states, 2 events) 0.12s 0.12s
machine.handle (3 states, 2 transitions) 0.18s 0.18s
Machine.invoke (state-dependent Effect) 0.27s 0.26s
machine.handle (depth 24) 0.43s 0.46s
machine.handle (wide depth 16) 0.47s 0.47s
machine.handle (parallel/history/choice) 0.36s 0.38s
machine.handle (4 successive calls) 0.39s 0.37s
machine exact input/output/error/services 0.33s 0.34s
execution adapter readiness 0.36s 0.37s

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 124,673 transitions/s
Drain burst with terminal fence 387,750 increments/s
Drain burst with a change observer 354,953 increments/s
Lookup and send to one child 316,972 increments/s
Start and stop a machine 152,602 machines/s
Start and stop a parent with one child 32,104 families/s
Plan transitions through a compound state 113,741 transitions/s
Plan transitions through parallel regions 88,560 transitions/s
Drain burst through a compound state 362,598 events/s
Drain burst through two parallel regions 337,941 events/s
Drain a compound-state burst with a change observer 342,600 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 15,169 processes/s
Start and stop a raw compiled process 63,171 processes/s
Memory profile Effect Machine
Idle machine 1.8 KiB
Raw generic managed process 13.9 KiB
Raw compiled process 3.1 KiB
Two independent idle machines 3.4 KiB
Idle parent with one child 5.5 KiB
Parent with observed child registry 9.7 KiB
Parent with observed invoked child snapshots 6.0 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 124,723 transitions/s 1.1% MAD 124,673 transitions/s 1.5% MAD -0.0%
Drain burst with terminal fence 385,510 increments/s 2.2% MAD 387,750 increments/s 2.2% MAD +0.6%
Drain burst with a change observer 360,185 increments/s 1.9% MAD 354,953 increments/s 1.7% MAD -1.5%
Lookup and send to one child 316,751 increments/s 2.5% MAD 316,972 increments/s 2.3% MAD +0.1%
Start and stop a machine 149,209 machines/s 1.3% MAD 152,602 machines/s 0.0% MAD +2.3%
Start and stop a parent with one child 31,142 families/s 2.5% MAD 32,104 families/s 6.4% MAD +3.1%
Plan transitions through a compound state 111,664 transitions/s 1.9% MAD 113,741 transitions/s 0.2% MAD +1.9%
Plan transitions through parallel regions 88,144 transitions/s 1.6% MAD 88,560 transitions/s 1.0% MAD +0.5%
Drain burst through a compound state 364,154 events/s 0.8% MAD 362,598 events/s 1.6% MAD -0.4%
Drain burst through two parallel regions 331,406 events/s 1.5% MAD 337,941 events/s 1.8% MAD +2.0%
Drain a compound-state burst with a change observer 340,756 events/s 1.0% MAD 342,600 events/s 1.4% MAD +0.5%
Idle machine heap per unit 1.8 KiB 0.1% MAD 1.8 KiB 0.0% MAD 0.0%
Raw generic managed process heap per unit 13.9 KiB 0.0% MAD 13.9 KiB 0.0% MAD +0.0%
Raw compiled process heap per unit 3.1 KiB 0.6% MAD 3.1 KiB 0.4% MAD -0.1%
Two independent idle machines heap per unit 3.4 KiB 0.0% MAD 3.4 KiB 0.0% MAD -0.0%
Idle parent with one child heap per unit 5.5 KiB 0.0% MAD 5.5 KiB 0.0% MAD 0.0%
Parent with observed child registry heap per unit 9.7 KiB 0.0% MAD 9.7 KiB 0.0% MAD -0.0%
Parent with observed invoked child snapshots heap per unit 6.0 KiB 0.0% MAD 6.0 KiB 0.1% MAD -0.0%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 15,549 processes/s 1.1% MAD 15,169 processes/s 0.8% MAD -2.4%
Start and stop a raw compiled process 62,185 processes/s 2.1% MAD 63,171 processes/s 1.5% MAD +1.6%

Regression guard

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

Versions and interpretation
  • Effect Machine: 0.12.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 aa4947f into main Aug 16, 2026
13 checks passed
@SandroMaglione
SandroMaglione deleted the codex/factory-only-invoke-effects branch August 16, 2026 14:21
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