Dashboard › opencode › Distillation
c5b390ba-0ee7-4555-b76d-817a7eea433a["lore_tm_v1_i33xm4NX1geNuaep5y442NOkvK2ybQ5LF7UvB5KGiik","lore_tm_v1_eh0HsluBGOfCf-XnXrv9gNjQrm2IKVvl-F9iMSynr-E","lore_tm_v1_ntDPQvdqmBAFTKbpt7MhhmSXZm5RkJ94ay_7lS35IAY","lore_tm_v1_zlNaqGdCpQB9ipVWSrrgA8QbPVCcMzSyOaYZdKY3vuk"]
Date: Sep 17, 2026
packages/core/test/session-runner.test.ts lines 838 (SessionEvent.Tool.Failed.type), 3924 (session.next.step.interrupted.1 trigger), 3940 (phase: "cancelling"), 3960 (SessionEvent.Step.Failed.type), 3994, 4063, 4097, and 4128 (session.next.step.interrupted.1), and 4102 (phase: "cancelling"); packages/core/test/session-tool-progress.test.ts lines 127 and 155 (SessionEvent.Tool.Failed publication/versioned event type); packages/core/test/session-execution-local.test.ts lines 310 and 350 (phase: "cancelling" claims); and packages/core/test/session-projector.test.ts line 285 (SessionEvent.Step.Failed) plus lines 2145, 2244, and 2296 (phase: "cancelling").packages/core/src/session/run-coordinator.ts:5-15 defines SessionRunCoordinator.Coordinator<Key, E> to serialize execution per key while allowing different keys to run concurrently. Its API is active (snapshot owned keys), run(key) (start while idle or join active execution), wake(key) (coalesce one follow-up), and interrupt(key, cleanup?) (stop active execution, clean up, then start work that arrived while stopping).packages/core/src/session/run-coordinator.ts:17-37 stores each active key in Map<Key, Entry<E>>; Entry<E> contains done: Deferred.Deferred<void, E>, optional interruption, optional owner Fiber, optional exit, plus pendingWake and stopping, initially both false. make() receives drain(key, force) and uses FiberSet.makeRuntime<never, void, never>().packages/core/src/session/run-coordinator.ts:39-51 starts a drain owner through the FiberSet: normal starts wait on a ready deferred, successor starts first Effect.yieldNow, then invoke options.drain(key, force). Effect.onExit calls settle(key, entry, exit), and the owner fiber is saved before a normal start’s ready gate is released.packages/core/src/session/run-coordinator.ts:53-71 settlement semantics: while entry.stopping, the exit is stored in entry.exit; a successful non-stopping execution with pendingWake clears the flag and restarts the same entry as a non-forced successor; otherwise an existing pendingWake creates and starts a replacement entry, while no pending wake removes the key. The original entry.done is then completed with its exit.packages/core/src/session/run-coordinator.ts:73-98 implements run(key) under Effect.uninterruptibleMask: callers join an active non-stopping entry, while callers encountering a stopping entry await its done and retry run(key); an idle key creates an entry and starts drain(key, true). wake(key) sets pendingWake = true when active, otherwise creates an entry and starts drain(key, false).packages/core/src/session/run-coordinator.ts:100-131 implements coalesced interruption: with no active owner, it executes cleanup; an existing entry.interruption is joined; otherwise it sets stopping = true, clears the current pendingWake, interrupts the owner, captures cleanup with Effect.exit, and requires the interrupted owner to have populated entry.exit, throwing Interrupted Session execution did not settle otherwise. If no work arrived during stopping, it deletes the key; if wake(key) set pendingWake during stopping, it installs a fresh successor and starts drain(key, false). It completes the old entry.done with the owner exit, propagates cleanup failure via Effect.failCause(cleanupExit.cause), runs the interruption sequence uninterruptibly, and completes the shared interruption deferred on exit.packages/core/src/session/run-coordinator.ts:133 returns { active: Effect.sync(() => new Set(active.keys())), run, wake, interrupt }, so active exposes a snapshot rather than the mutable backing map.