Skip to content

Move initial edges and data construction into handlers - #212

Merged
SandroMaglione merged 2 commits into
mainfrom
codex/handler-initial-edges
Sep 9, 2026
Merged

Move initial edges and data construction into handlers#212
SandroMaglione merged 2 commits into
mainfrom
codex/handler-initial-edges

Conversation

@SandroMaglione

@SandroMaglione SandroMaglione commented Sep 9, 2026

Copy link
Copy Markdown
Member

Summary

Initial targets and their data are now declared together in .handle, so structural state definitions can be reused without carrying executable startup choices. Machine.make no longer accepts initial or initialConfiguration.

Compound handlers declare initial: { target, data? }; parallel handlers declare region data in an initial map. The root handler accepts root: value or root: ({ input }) => value. Declarative constructors use data and { decoded: true, data }; command-producing initialization moves to entry/exit or invocation handlers.

The migration preserves inspectable initial edges, direct-child target checking, required constructors, typed Effect requirements and failures, and generic/optimized startup behavior. Runtime tests, negative type tests with valid baselines, completion checks, examples, lint rules, packaged consumers, and API documentation are updated.

Changeset

  • Added or updated for a library or package-metadata change
  • Not required because this PR does not change a publishable package

The minor changeset covers the four packages in the fixed release group and documents direct migration.

Validation

  • pnpm check
  • Automated type-performance measurement passed or was not required
  • Automated runtime- and memory-performance measurement passed or was not required

Local pnpm perf:types and pnpm perf:runtime passed. CI passed all checks on 5336a4b, including the paired type and runtime/memory reports. Startup is 8–9% below the base, within the existing 15% guard; event throughput and memory are effectively unchanged. Type counts remain within the existing budgets, with improvements for deeper handler trees and added initialization-checking cost in smaller fixtures.

@github-actions

github-actions Bot commented Sep 9, 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.state (3 children) 3,555 3,521 -34 (-1.0%)
Machine.make (3 states, 2 events) 9,947 9,491 -456 (-4.6%)
machine.handle (3 states, 2 transitions) 44,639 49,816 +5,177 (+11.6%)
declared transition (10 named branches) 69,242 66,784 -2,458 (-3.5%)
atomic construction, guards, and reentry 84,173 91,682 +7,509 (+8.9%)
registered invocation (input-taking Effect) 41,505 49,109 +7,604 (+18.3%)
machine.handle (depth 24) 206,652 197,583 -9,069 (-4.4%)
machine.handle (wide depth 16) 261,155 221,254 -39,901 (-15.3%)
machine.handle (parallel/history/choice) 103,899 101,203 -2,696 (-2.6%)
machine definition (3 independent implementations) 99,511 102,696 +3,185 (+3.2%)
machine exact input/output/error/services 78,268 88,468 +10,200 (+13.0%)
execution adapter readiness 83,053 75,683 -7,370 (-8.9%)

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

Scenario Base PR Difference
Import effect-machine 0 0 0
Machine.state (3 children) 3,500 3,466 -34 (-1.0%)
Machine.make (3 states, 2 events) 6,384 5,962 -422 (-6.6%)
machine.handle (3 states, 2 transitions) 34,692 40,325 +5,633 (+16.2%)
declared transition (10 named branches) 51,876 57,673 +5,797 (+11.2%)
atomic construction, guards, and reentry 64,391 75,870 +11,479 (+17.8%)
registered invocation (input-taking Effect) 27,935 41,409 +13,474 (+48.2%)
machine.handle (depth 24) 133,290 179,729 +46,439 (+34.8%)
machine.handle (wide depth 16) 183,676 204,178 +20,502 (+11.2%)
machine.handle (parallel/history/choice) 77,894 88,160 +10,266 (+13.2%)
machine definition (3 independent implementations) 77,332 91,471 +14,139 (+18.3%)
machine exact input/output/error/services 57,595 75,730 +18,135 (+31.5%)
execution adapter readiness 24,278 23,335 -943 (-3.9%)
Check times (informational)
Scenario Base PR
Effect only 0.03s 0.05s
Import effect-machine 0.03s 0.03s
Machine.state (3 children) 0.11s 0.11s
Machine.make (3 states, 2 events) 0.16s 0.15s
machine.handle (3 states, 2 transitions) 0.31s 0.34s
declared transition (10 named branches) 0.41s 0.42s
atomic construction, guards, and reentry 0.51s 0.52s
registered invocation (input-taking Effect) 0.32s 0.34s
machine.handle (depth 24) 0.61s 0.63s
machine.handle (wide depth 16) 0.75s 0.69s
machine.handle (parallel/history/choice) 0.53s 0.53s
machine definition (3 independent implementations) 0.53s 0.55s
machine exact input/output/error/services 0.48s 0.52s
execution adapter readiness 0.50s 0.45s

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

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Runtime performance

Median of 5 independent benchmark processes on AMD EPYC 9V74 80-Core Processor with Node v24.20.0.

Pull request baseline

Scenario Effect Machine
Plan counter transitions 139,627 transitions/s
Drain burst with terminal fence 432,011 increments/s
Drain burst with a change observer 406,462 increments/s
Lookup and send to one child 365,021 increments/s
Start and stop a machine 147,710 machines/s
Start and stop a parent with one child 43,584 families/s
Plan transitions through a compound state 123,053 transitions/s
Plan transitions through parallel regions 100,990 transitions/s
Drain burst through a compound state 341,009 events/s
Drain burst through two parallel regions 323,798 events/s
Drain a compound-state burst with a change observer 322,335 events/s

Process runtime reference points

Scenario Effect Machine
Start and stop a raw generic process 33,575 processes/s
Start and stop a raw compiled process 82,727 processes/s
Memory profile Effect Machine
Idle machine 1.9 KiB
Raw generic managed process 13.9 KiB
Raw compiled process 3.2 KiB
Two independent idle machines 3.6 KiB
Idle parent with one child 5.9 KiB
Parent with observed child registry 10.0 KiB
Parent with observed invoked child snapshots 6.5 KiB

Effect Machine change from base

Metric Base Base variability PR PR variability Difference
Plan counter transitions 138,922 transitions/s 1.3% MAD 139,627 transitions/s 0.6% MAD +0.5%
Drain burst with terminal fence 435,000 increments/s 1.7% MAD 432,011 increments/s 1.1% MAD -0.7%
Drain burst with a change observer 404,827 increments/s 2.4% MAD 406,462 increments/s 1.1% MAD +0.4%
Lookup and send to one child 371,471 increments/s 2.4% MAD 365,021 increments/s 0.4% MAD -1.7%
Start and stop a machine 162,893 machines/s 0.7% MAD 147,710 machines/s 0.7% MAD -9.3%
Start and stop a parent with one child 47,436 families/s 0.1% MAD 43,584 families/s 0.4% MAD -8.1%
Plan transitions through a compound state 123,753 transitions/s 1.5% MAD 123,053 transitions/s 0.5% MAD -0.6%
Plan transitions through parallel regions 100,689 transitions/s 1.8% MAD 100,990 transitions/s 0.9% MAD +0.3%
Drain burst through a compound state 342,464 events/s 0.6% MAD 341,009 events/s 2.2% MAD -0.4%
Drain burst through two parallel regions 322,006 events/s 0.7% MAD 323,798 events/s 1.8% MAD +0.6%
Drain a compound-state burst with a change observer 325,029 events/s 0.3% MAD 322,335 events/s 2.2% MAD -0.8%
Idle machine heap per unit 1.9 KiB 0.4% MAD 1.9 KiB 2.1% MAD +2.9%
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.2 KiB 0.4% MAD 3.2 KiB 0.2% MAD +1.1%
Two independent idle machines heap per unit 3.5 KiB 0.0% MAD 3.6 KiB 0.4% MAD +0.8%
Idle parent with one child heap per unit 5.9 KiB 0.0% MAD 5.9 KiB 0.0% MAD +0.2%
Parent with observed child registry heap per unit 10.0 KiB 0.0% MAD 10.0 KiB 0.0% MAD -0.1%
Parent with observed invoked child snapshots heap per unit 6.5 KiB 0.1% MAD 6.5 KiB 0.2% MAD -0.3%

Process runtime reference change from base

Metric Base Base variability PR PR variability Difference
Start and stop a raw generic process 33,586 processes/s 0.0% MAD 33,575 processes/s 1.7% MAD -0.0%
Start and stop a raw compiled process 82,590 processes/s 0.8% MAD 82,727 processes/s 1.0% MAD +0.2%

Regression guard

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

Versions and interpretation
  • Effect Machine: 0.34.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 e72b7f5 into main Sep 9, 2026
8 checks passed
@SandroMaglione
SandroMaglione deleted the codex/handler-initial-edges branch September 9, 2026 16:48
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