A subscription callback that writes an Atom.fn while AtomRegistry.batch() is committing loses that write permanently. This occurs with a synchronously available source value; moving the source response to a later tick avoids it. The callback is a normal registry subscription, and the write is a normal registry.set.
Reproduction
Install effect@4.0.0-rc.117 and run this with Bun (bun repro.ts):
import assert from 'node:assert/strict'
import { Effect } from 'effect'
import * as Atom from 'effect/unstable/reactivity/Atom'
import * as AtomRegistry from 'effect/unstable/reactivity/AtomRegistry'
const registry = AtomRegistry.make()
const source = Atom.make(0)
const write = Atom.fn((value: number, get) =>
Effect.sync(() => get.registry.set(source, value)),
)
const seen: number[] = []
registry.mount(write)
registry.subscribe(source, (value) => seen.push(value))
registry.subscribe(source, (value) => {
if (value === 1) registry.set(write, 2)
})
AtomRegistry.batch(() => registry.set(source, 1))
console.log({ source: registry.get(source), seen })
assert.equal(registry.get(source), 2)
assert.deepEqual(seen, [1, 2])
Expected: source: 2, seen: [1, 2]. Actual: source: 1, seen: [1]; the first assertion fails (1 !== 2).
Atom.fn's write calls batch() internally. During the outer batch's notify/commit loop, that nested batch changes the shared phase back to collect and queues the function node for rebuild. Its depth is 2 so it does not flush; the outer batch has already completed its stale rebuild pass. The queued rebuild is then discarded when the outer batch clears stale, without running the function. Nested batches entered from commit callbacks need their stale rebuilds flushed before the outer commit finishes.
Versions: effect@4.0.0-rc.117, Bun 1.4.2, Linux x64. Also observed in the consuming app on effect@4.0.0-rc.112.
Posted on behalf of @schickling
| field |
value |
agent_identity |
dev3.direct.omp.de5nueza |
session |
unknown |
agent_persona |
generalist |
agent_supervisor |
unavailable |
agent_tool |
OMP |
agent_tool_version |
18.3.0 |
agent_runtime |
OMP 18.3.0 |
agent_model |
openai-codex/gpt-6-sol |
worktree |
unknown |
tooling_profile |
dotfiles@bcd0eca |
A subscription callback that writes an
Atom.fnwhileAtomRegistry.batch()is committing loses that write permanently. This occurs with a synchronously available source value; moving the source response to a later tick avoids it. The callback is a normal registry subscription, and the write is a normalregistry.set.Reproduction
Install
effect@4.0.0-rc.117and run this with Bun (bun repro.ts):Expected:
source: 2,seen: [1, 2]. Actual:source: 1,seen: [1]; the first assertion fails (1 !== 2).Atom.fn's write callsbatch()internally. During the outer batch's notify/commit loop, that nested batch changes the shared phase back tocollectand queues the function node for rebuild. Its depth is 2 so it does not flush; the outer batch has already completed its stale rebuild pass. The queued rebuild is then discarded when the outer batch clearsstale, without running the function. Nested batches entered from commit callbacks need their stale rebuilds flushed before the outer commit finishes.Versions:
effect@4.0.0-rc.117, Bun 1.4.2, Linux x64. Also observed in the consuming app oneffect@4.0.0-rc.112.Posted on behalf of @schickling
agent_identitysessionagent_personaagent_supervisoragent_toolagent_tool_versionagent_runtimeagent_modelworktreetooling_profile