Skip to content

Added module for Machine - #6429

Closed
SandroMaglione wants to merge 10 commits into
Effect-TS:mainfrom
SandroMaglione:sandro/state-charts
Closed

Added module for Machine#6429
SandroMaglione wants to merge 10 commits into
Effect-TS:mainfrom
SandroMaglione:sandro/state-charts

Conversation

@SandroMaglione

@SandroMaglioneSandroMaglione commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Type

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Description

Added Machine module with Atom adapter:

  • Machine ("state chart")
  • AtomMachine integration for effect-atom

The feature is exposed under effect/unstable/machine.

import{Machine}from"effect/unstable/machine"classCartextendsSchema.TaggedClass<Cart>("Cart")("Cart",{orderId: Schema.String}){}classEditingextendsSchema.TaggedClass<Editing>("Editing")("Editing",{}){}classReviewingextendsSchema.TaggedClass<Reviewing>("Reviewing")("Reviewing",{}){}classCheckoutextendsSchema.TaggedClass<Checkout>("Checkout")("Checkout",{orderId: Schema.String}){}classPaymentextendsSchema.TaggedClass<Payment>("Payment")("Payment",{status: Schema.Literals(["pending","paid"])}){}classDeliveryextendsSchema.TaggedClass<Delivery>("Delivery")("Delivery",{status: Schema.Literals(["label","shipped"])}){}classReviewextendsSchema.TaggedClass<Review>("Review")("Review",{}){}classSubmitextendsSchema.TaggedClass<Submit>("Submit")("Submit",{orderId: Schema.String}){}constOrderStates=Machine.defineStates({cart: {schema: Cart,initial: "editing",states: {editing: Editing,reviewing: Reviewing}},checkout: {schema: Checkout,type: "parallel",states: {payment: Payment,delivery: Delivery}}})constorderMachine=Machine.make({id: "Order",states: OrderStates.states,events: [Review,Submit],initial: ()=>OrderStates.initial.cart(newCart({orderId: "order-1"}),(cart)=>cart.editing(newEditing({})))}).handle({cart: {states: {editing: {on: {Review: ({ target })=>target.local.reviewing(newReviewing({}))}},reviewing: {on: {Submit: ({ event, target })=>target.full.checkout(newCheckout({orderId: event.orderId}),(checkout)=>checkout.payment(newPayment({status: "pending"})).delivery(newDelivery({status: "label"})))}}}}})

Feel free to push back on any of the API decisions or to propose or ask for any change.

Related

Moved over from the effect-smol PR.

This work is inspired by xstate, and it builds on top of #1945.

Summary by CodeRabbit

  • New Features
    • Added an unstable, schema-first Machine API with typed planning/execution, snapshot encode/decode, and runtime/process helpers.
    • Exposed a new public entrypoint for the unstable machine API.
    • Added AtomMachine integration for reactive snapshot tracking, typed event sending, and coordinated stopping.
    • Added ClusterMachine adapter to persist checkpoints, deduplicate requests, and resume from stored snapshots.
  • Tests
    • Added extensive runtime tests and TypeScript typetests for Machine, AtomMachine, and ClusterMachine.
  • Chores
    • Added a patch release Changeset documenting the new unstable APIs.

@changeset-bot

changeset-botBot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c951c76

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 27 packages
NameType
effectPatch
@effect/opentelemetryPatch
@effect/platform-browserPatch
@effect/platform-bunPatch
@effect/platform-node-sharedPatch
@effect/platform-nodePatch
@effect/vitestPatch
@effect/ai-anthropicPatch
@effect/ai-openai-compatPatch
@effect/ai-openaiPatch
@effect/ai-openrouterPatch
@effect/atom-reactPatch
@effect/atom-solidPatch
@effect/atom-vuePatch
@effect/sql-clickhousePatch
@effect/sql-d1Patch
@effect/sql-libsqlPatch
@effect/sql-mssqlPatch
@effect/sql-mysql2Patch
@effect/sql-pgPatch
@effect/sql-pglitePatch
@effect/sql-sqlite-bunPatch
@effect/sql-sqlite-doPatch
@effect/sql-sqlite-nodePatch
@effect/sql-sqlite-react-nativePatch
@effect/sql-sqlite-wasmPatch
@effect/openapi-generatorPatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@IMax153IMax153 added the 4.0 label Jul 16, 2026
@IMax153
IMax153 requested a review from mikearnaldiJuly 19, 2026 17:28
@IMax153IMax153 added the enhancement New feature or request label Jul 19, 2026
@tim-smart

Copy link
Copy Markdown
Contributor

What does the cluster integration look like?

@coderabbitai

coderabbitaiBot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@tim-smart, you've reached your PR review limit, so we couldn't start this review.

Next review available in:18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 647bcffd-1e50-46b5-b3e9-30f03d010558

📥 Commits

Reviewing files that changed from the base of the PR and between dd4bdc8 and c951c76.

📒 Files selected for processing (11)
  • packages/effect/src/unstable/machine/Machine.ts
  • packages/effect/src/unstable/machine/internal/machineErrors.ts
  • packages/effect/src/unstable/machine/internal/machineModel.ts
  • packages/effect/src/unstable/machine/internal/machinePlanner.ts
  • packages/effect/src/unstable/machine/internal/machineProcess.ts
  • packages/effect/src/unstable/machine/internal/machineRuntime.ts
  • packages/effect/src/unstable/reactivity/AtomMachine.ts
  • packages/effect/test/reactivity/AtomMachine.test.ts
  • packages/effect/test/unstable/machine/Machine.test.ts
  • packages/effect/typetest/Machine.tst.ts
  • packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts
📝 Walkthrough

Walkthrough

A new unstable schema-first Machine API adds typed state modeling, transition planning, snapshot serialization, managed process lifecycles, child orchestration, AtomMachine reactivity, and ClusterMachine persistence. Runtime tests and compile-time type tests cover these behaviors.

Changes

Machine platform and integrations

Layer / File(s)Summary
Public Machine contracts and builders
packages/effect/package.json, packages/effect/src/unstable/machine/Machine.ts, packages/effect/src/unstable/machine/index.ts, packages/effect/src/unstable/machine/internal/machineErrors.ts, packages/effect/typetest/Machine.tst.ts, .changeset/*
Adds typed state definitions, handlers, targets, runtime capabilities, tagged errors, public exports, release metadata, and compile-time validation.
State configuration and snapshot persistence
packages/effect/src/unstable/machine/internal/machineModel.ts, packages/effect/test/unstable/machine/Machine.test.ts
Compiles state trees, normalizes configurations and targets, resolves completion outputs, and encodes or decodes schema-validated snapshots.
Transition planning and macrosteps
packages/effect/src/unstable/machine/internal/machinePlanner.ts, packages/effect/test/unstable/machine/Machine.test.ts
Implements transition selection, microsteps, macrosteps, raised and emitted events, staged actions, completion routing, and transition validation.
Process lifecycle and child execution
packages/effect/src/unstable/machine/internal/machineProcess.ts, packages/effect/src/unstable/machine/internal/machineRuntime.ts, packages/effect/test/unstable/machine/Machine.test.ts
Adds managed execution, snapshot publication, invocation and child-process handling, terminalization, stopping, and lifecycle coverage.
AtomMachine state synchronization
packages/effect/src/unstable/reactivity/AtomMachine.ts, packages/effect/src/unstable/reactivity/index.ts, packages/effect/test/reactivity/AtomMachine.test.ts, packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts
Exposes ref, snapshot, state, send, and stop atoms backed by a scoped MachineRef, including startup, failure, completion, and service-access behavior.
ClusterMachine checkpoint persistence
packages/effect/src/unstable/cluster/ClusterMachine.ts, packages/effect/src/unstable/cluster/index.ts, packages/effect/test/cluster/ClusterMachine.test.ts, packages/effect/typetest/ClusterMachine.tst.ts
Adds persisted checkpoint loading and commits, request deduplication, durable emissions, rejection outcomes, in-memory storage, rollback behavior, and type-level integration checks.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
participant AtomMachine
participant MachineStart
participant machinePlanner
participant machineRuntime
participant MachineRef
AtomMachine->>MachineStart: start machine
MachineStart->>machinePlanner: plan initial state
MachineStart->>machineRuntime: create managed process
machineRuntime-->>MachineRef: publish snapshots and lifecycle operations
AtomMachine->>MachineRef: send event or stop
MachineRef-->>AtomMachine: stream runtime snapshot
Loading

Suggested reviewers:mikearnaldi

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check nameStatusExplanationResolution
Title check❓ InconclusiveThe title is related to the change, but it is too vague and generic to describe the main update.Use a concise, specific title such as "Add unstable Machine module and AtomMachine integration".
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (3)
packages/effect/src/unstable/machine/internal/machineProcess.ts (2)

142-171: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Deduplicate stopInvoke/clearInvoke.

The two helpers differ only in the token guard inside Ref.modify; the Scope.close + stopChild cleanup that follows is identical. Extract the common cleanup so the two lifecycle-teardown paths can't drift.

♻️ Sketch
+ const closeSession = (session: InvokeSession | undefined, exit: Exit.Exit<unknown, unknown>): Effect.Effect<void> =>+ session === undefined+ ? Effect.void+ : Scope.close(session.scope, exit).pipe(Effect.andThen(context.stopChild(session.childId)))
const stopInvoke = (key: string, exit: Exit.Exit<unknown, unknown>): Effect.Effect<void> =>
Ref.modify(invokeSessions, (sessions) => {
const current = HashMap.get(sessions, key)
return Option.isSome(current)
? [current.value, HashMap.remove(sessions, key)] as const
: [undefined, sessions] as const
- }).pipe(- Effect.flatMap((session) =>- session === undefined- ? Effect.void- : Scope.close(session.scope, exit).pipe(- Effect.andThen(context.stopChild(session.childId))- )- )- )+ }).pipe(Effect.flatMap((session) => closeSession(session, exit)))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/src/unstable/machine/internal/machineProcess.ts` around lines
142 - 171, Deduplicate the identical cleanup in stopInvoke and clearInvoke by
extracting a shared helper that removes or receives the invoke session and
performs Scope.close followed by context.stopChild. Keep the token guard in
clearInvoke and the unguarded lookup in stopInvoke, while routing both through
the shared teardown logic.

185-192: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Effect.fnUntraced for the invoke helpers that only return Effect.gen. Both helpers currently return a bare Effect.gen, inconsistent with startInvokes in the same file which already uses Effect.fnUntraced.

  • packages/effect/src/unstable/machine/internal/machineProcess.ts#L185-L192: rewrite startInvokeWatchers as Effect.fnUntraced(function*(config, child, key, token, scope) { ... }).
  • packages/effect/src/unstable/machine/internal/machineProcess.ts#L236-L241: rewrite startInvoke as Effect.fnUntraced(function*(path, config, state, event) { ... }).

As per coding guidelines: "prefer Effect.fnUntraced over functions that only return Effect.gen".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/src/unstable/machine/internal/machineProcess.ts` around lines
185 - 192, Update startInvokeWatchers and startInvoke in
packages/effect/src/unstable/machine/internal/machineProcess.ts at lines 185-192
and 236-241 to use Effect.fnUntraced with their existing generator bodies and
parameters, matching the established startInvokes pattern; no other behavior
should change.

Source: Coding guidelines

packages/effect/src/unstable/reactivity/AtomMachine.ts (1)

28-39: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding a typetest for the make overload's EnsureNoExternalRequirements/ExcludeCompatibleMachineRuntime constraint.

This conditional-type machinery decides whether the first make overload (no external AtomRuntime) is usable for a given machine, based on comparing Requirements against Machine.Runtime.Requirement<Events, Emits>. It's intricate enough (nested conditionals, IsAny guard) that a regression here would silently change which machines type-check without an AtomRuntime, and there's no dedicated typetest for AtomMachine in this cohort (only packages/effect/typetest/Machine.tst.ts for the base Machine API).

As per path instructions, packages/*/typetest/**/*.{ts,tsx} is the place for type-level tests, run via pnpm test-types <filename>.

Also applies to: 231-358

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/src/unstable/reactivity/AtomMachine.ts` around lines 28 - 39,
Add a dedicated AtomMachine typetest under the package typetest area covering
the make overload’s EnsureNoExternalRequirements constraint, including
compatible, incompatible, and any/unknown requirement cases governed by
ExcludeCompatibleMachineRuntime. Assert which machines type-check with and
without an external AtomRuntime, and run it with the package’s test-types
command.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/effect/src/unstable/machine/internal/machineProcess.ts`:
- Around line 203-206: Update the snapshot-mapped send in the machine process
flow, after mapSnapshot returns a defined event, to catch and ignore
StoppedError from context.self.send. Mirror the existing Done relay’s
Effect.catchTag("StoppedError", ...) handling while preserving Effect.void for
undefined mapped events.
In `@packages/effect/src/unstable/reactivity/AtomMachine.ts`:
- Around line 191-214: Update the send and stop writable handlers to make
non-Success ref states observable instead of silently returning. When ref is
Initial or Failure, propagate an appropriate AsyncResult failure through the
atom’s own state using the existing StartError or Machine.StoppedError types;
preserve the current Effect.runCallback behavior for Success and ensure calls
are not silently dropped.
In `@packages/effect/test/unstable/machine/Machine.test.ts`:
- Around line 5468-5526: In
packages/effect/test/unstable/machine/Machine.test.ts ranges 5468-5526 and
5541-5601, fix the vacuous stoppedOutcomes checks in both invoke-lifecycle
tests: either connect stoppedOutcomes to the stopped-outcome observation path so
the zero assertion verifies behavior, or remove the unused counter and its
assert.strictEqual assertion from both tests.
---
Nitpick comments:
In `@packages/effect/src/unstable/machine/internal/machineProcess.ts`:
- Around line 142-171: Deduplicate the identical cleanup in stopInvoke and
clearInvoke by extracting a shared helper that removes or receives the invoke
session and performs Scope.close followed by context.stopChild. Keep the token
guard in clearInvoke and the unguarded lookup in stopInvoke, while routing both
through the shared teardown logic.
- Around line 185-192: Update startInvokeWatchers and startInvoke in
packages/effect/src/unstable/machine/internal/machineProcess.ts at lines 185-192
and 236-241 to use Effect.fnUntraced with their existing generator bodies and
parameters, matching the established startInvokes pattern; no other behavior
should change.
In `@packages/effect/src/unstable/reactivity/AtomMachine.ts`:
- Around line 28-39: Add a dedicated AtomMachine typetest under the package
typetest area covering the make overload’s EnsureNoExternalRequirements
constraint, including compatible, incompatible, and any/unknown requirement
cases governed by ExcludeCompatibleMachineRuntime. Assert which machines
type-check with and without an external AtomRuntime, and run it with the
package’s test-types command.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 5a901101-5411-4517-9368-c01db2f3365a

📥 Commits

Reviewing files that changed from the base of the PR and between 46997fa and ffb7a9f.

📒 Files selected for processing (14)
  • .changeset/public-towns-invent.md
  • packages/effect/package.json
  • packages/effect/src/unstable/machine/Machine.ts
  • packages/effect/src/unstable/machine/index.ts
  • packages/effect/src/unstable/machine/internal/machineErrors.ts
  • packages/effect/src/unstable/machine/internal/machineModel.ts
  • packages/effect/src/unstable/machine/internal/machinePlanner.ts
  • packages/effect/src/unstable/machine/internal/machineProcess.ts
  • packages/effect/src/unstable/machine/internal/machineRuntime.ts
  • packages/effect/src/unstable/reactivity/AtomMachine.ts
  • packages/effect/src/unstable/reactivity/index.ts
  • packages/effect/test/reactivity/AtomMachine.test.ts
  • packages/effect/test/unstable/machine/Machine.test.ts
  • packages/effect/typetest/Machine.tst.ts

Comment threadpackages/effect/src/unstable/machine/internal/machineProcess.ts Outdated
Comment threadpackages/effect/src/unstable/reactivity/AtomMachine.ts Outdated
Comment threadpackages/effect/test/unstable/machine/Machine.test.ts Outdated

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/effect/src/unstable/cluster/ClusterMachine.ts (1)

304-305: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Hoist hasInvokes(machine) out of the per-request hot path.

hasInvokes scans Reflect.ownKeys(machine.handlers) on every single send call, but machine.handlers never changes after make() builds the layer. Compute it once alongside machineId (Line 495) and capture it in the closure instead of recomputing per request.

♻️ Proposed refactor
 const entity = Entity.make(type, [rpc])
const machineId = machine.id ?? type
+ const invokesUnsupported = hasInvokes(machine)
- const handle = Effect.fnUntraced(function*(request: Entity.Request<SendRpc<MachineEvents<M>>>) {- if (hasInvokes(machine)) {+ const handle = Effect.fnUntraced(function*(request: Entity.Request<SendRpc<MachineEvents<M>>>) {+ if (invokesUnsupported) {
return yield* fail(

Also applies to: 513-519

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/src/unstable/cluster/ClusterMachine.ts` around lines 304 -
305, Move the hasInvokes(machine) computation out of the per-request send path
and calculate it once during machine setup alongside machineId. Capture the
resulting boolean in the closure, then update the send handling around the
hasInvokes references at lines 513-519 to use that cached value while preserving
existing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/effect/src/unstable/cluster/ClusterMachine.ts`:
- Around line 317-326: Update rejectionFromCause to inspect defects via
Cause.findDefect in addition to the existing Cause.findErrorOption path, and
convert a discovered Machine.ProcessLocalError into the existing
UnsupportedProcessLocal rejection. Preserve Rejected handling and
TransitionFailure fallback for all other causes.
---
Nitpick comments:
In `@packages/effect/src/unstable/cluster/ClusterMachine.ts`:
- Around line 304-305: Move the hasInvokes(machine) computation out of the
per-request send path and calculate it once during machine setup alongside
machineId. Capture the resulting boolean in the closure, then update the send
handling around the hasInvokes references at lines 513-519 to use that cached
value while preserving existing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3cbfa41f-e431-490b-902e-0abbdb0cc679

📥 Commits

Reviewing files that changed from the base of the PR and between ffb7a9f and fab6dfd.

📒 Files selected for processing (9)
  • .changeset/public-towns-invent.md
  • packages/effect/src/unstable/cluster/ClusterMachine.ts
  • packages/effect/src/unstable/cluster/index.ts
  • packages/effect/src/unstable/machine/Machine.ts
  • packages/effect/src/unstable/machine/internal/machineErrors.ts
  • packages/effect/test/cluster/ClusterMachine.test.ts
  • packages/effect/test/unstable/machine/Machine.test.ts
  • packages/effect/typetest/ClusterMachine.tst.ts
  • packages/effect/typetest/Machine.tst.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • .changeset/public-towns-invent.md
  • packages/effect/src/unstable/machine/internal/machineErrors.ts
  • packages/effect/src/unstable/machine/Machine.ts
  • packages/effect/test/unstable/machine/Machine.test.ts
  • packages/effect/typetest/Machine.tst.ts

Comment on lines +317 to +326
const rejectionFromCause = (cause: Cause.Cause<unknown>): Rejected => {
const error = Cause.findErrorOption(cause)
if (Option.isSome(error) && error.value instanceof Rejected) {
return error.value
}
if (Option.isSome(error) && error.value instanceof Machine.ProcessLocalError) {
return reject("UnsupportedProcessLocal", `${error.value.operation} is process-local and is not supported`)
}
return reject("TransitionFailure", messageFromCause(cause))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== ClusterMachine.ts slices ==\n'
sed -n '300,340p' packages/effect/src/unstable/cluster/ClusterMachine.ts
printf'\n== ClusterMachine.ts raise slice ==\n'
sed -n '540,565p' packages/effect/src/unstable/cluster/ClusterMachine.ts
printf'\n== Search Cause helpers ==\n'
rg -n "findErrorOption|findDefect|failureOption|dieOption" packages/effect/src -g '!*dist*' -g '!*build*'printf'\n== Relevant Cause file candidates ==\n'
fd -a "Cause.ts" packages/effect/src | head -20
printf'\n== ClusterMachine test slice ==\n'
sed -n '560,610p' packages/effect/test/cluster/ClusterMachine.test.ts

Repository: Effect-TS/effect

Length of output: 8659


🏁 Script executed:

#!/bin/bashset -euo pipefail
printf'\n== Cause.ts find helpers ==\n'
sed -n '830,970p' packages/effect/src/Cause.ts
printf'\n== ClusterMachine.ts around line 600 ==\n'
sed -n '592,628p' packages/effect/src/unstable/cluster/ClusterMachine.ts

Repository: Effect-TS/effect

Length of output: 5234


ProcessLocalError needs to be read from defects too.runtime.raise throws Machine.ProcessLocalError with Effect.die, but Cause.findErrorOption only sees Fail causes. This branch misses the UnsupportedProcessLocal rejection for RaiseFromAction and falls through to TransitionFailure. Search Cause.findDefect here as well, or route ProcessLocalError through a typed failure.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/src/unstable/cluster/ClusterMachine.ts` around lines 317 -
326, Update rejectionFromCause to inspect defects via Cause.findDefect in
addition to the existing Cause.findErrorOption path, and convert a discovered
Machine.ProcessLocalError into the existing UnsupportedProcessLocal rejection.
Preserve Rejected handling and TransitionFailure fallback for all other causes.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts (1)

32-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use Effect.fnUntraced for these generator handlers.

  • packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts#L32-L36
  • packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts#L52-L55
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts` around lines
32 - 36, Replace the Effect.fn wrappers around both generator handlers in
AtomMachine.tst.ts at lines 32-36 and 52-55 with Effect.fnUntraced, preserving
each handler’s existing generator logic and behavior.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts`:
- Around line 32-36: Replace the Effect.fn wrappers around both generator
handlers in AtomMachine.tst.ts at lines 32-36 and 52-55 with Effect.fnUntraced,
preserving each handler’s existing generator logic and behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 19a55931-b92a-42db-b5b0-3d519e119a34

📥 Commits

Reviewing files that changed from the base of the PR and between fab6dfd and bd3f8da.

📒 Files selected for processing (5)
  • packages/effect/src/unstable/machine/internal/machineProcess.ts
  • packages/effect/src/unstable/reactivity/AtomMachine.ts
  • packages/effect/test/reactivity/AtomMachine.test.ts
  • packages/effect/test/unstable/machine/Machine.test.ts
  • packages/effect/typetest/unstable/reactivity/AtomMachine.tst.ts
💤 Files with no reviewable changes (1)
  • packages/effect/test/unstable/machine/Machine.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/effect/src/unstable/machine/internal/machineProcess.ts

@SandroMaglione

Copy link
Copy Markdown
ContributorAuthor

What does the cluster integration look like?

I added a ClusterMachine module to bridge Machine into cluster.

I am trying to find the best way to make the PR easier to review, since it contains quite a few additions. Let me know what you think I can do to ease the review

@SandroMaglione

Copy link
Copy Markdown
ContributorAuthor

Published a community library based on this PR at @typeonce/effect-machine

I intent to keep this in sync with the PR, so that people can test the API while it's being implemented

@tim-smart

Copy link
Copy Markdown
Contributor

Published a community library based on this PR at @typeonce/effect-machine

I intent to keep this in sync with the PR, so that people can test the API while it's being implemented

I think for the time being all development should happen in your repository. It is often what I do myself before introducing a new module to effect (effect atom is one example).

I'm going to close this for now and we can consider bringing your package into core once v4 is released and your package has had some time to settle.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

4.0enhancementNew feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@SandroMaglione@tim-smart@IMax153